diff --git a/django_comments_ink/__init__.py b/django_comments_ink/__init__.py index 2330422..a0e24bd 100644 --- a/django_comments_ink/__init__.py +++ b/django_comments_ink/__init__.py @@ -32,7 +32,7 @@ def get_form_target(): return reverse("comments-ink-post") -VERSION = (0, 0, 1, "a", 0) # following PEP 440 +VERSION = (0, 0, 2, "a", 0) # following PEP 440 def get_version(): diff --git a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.js b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.js similarity index 99% rename from django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.js rename to django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.js index 80e8725..0c2e5b0 100644 --- a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.js +++ b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.js @@ -934,4 +934,4 @@ window.addEventListener("DOMContentLoaded", (_) => { /******/ })() ; -//# sourceMappingURL=dci-0.0.1.js.map \ No newline at end of file +//# sourceMappingURL=dci-0.0.2.js.map \ No newline at end of file diff --git a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.js.map b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.js.map similarity index 99% rename from django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.js.map rename to django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.js.map index 6c58e7b..5e84877 100644 --- a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.js.map +++ b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.js.map @@ -1 +1 @@ -{"version":3,"file":"dci-0.0.1.js","mappings":";;;;;;;;;;;;;;AAAe;AACf;AACA;AACA;AACA;;AAEA,uBAAuB;;AAEvB,0BAA0B;;AAE1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,SAAS;AACT;AACA;AACA,cAAc;AACd;AACA;AACA,SAAS;;AAET;AACA,sBAAsB;AACtB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,iBAAiB;AACpE;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,mDAAmD,iBAAiB;AACpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AC/G4C;AACK;;;AAGjD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC,wDAAW;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,uDAAiB;AAC9D;AACA;;AAEyB;;;;;;;;;;;;;;;;AC1C0B;;AAEnD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,2CAA2C,0DAAgB;AAC3D;AACA;AACA,SAAS;;AAET;AACA;;AAE0B;;;;;;;;;;;;;;;;AC3BqB;;AAEhC;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,SAAS;AACjE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,wDAAc;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,2DAA2D;AAC3D;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC7IA;AACA;;AAEA;AACA;AACA;AACA,gDAAgD;AAChD,wBAAwB,oBAAoB;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEe;AACf,iBAAiB,2CAA2C;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,6BAA6B;AAC7B,4BAA4B;;AAE5B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,aAAa;AACb,UAAU;AACV,sCAAsC,eAAe,QAAQ,cAAc;AAC3E;AACA;;AAEA;AACA;AACA;AACA,qDAAqD,gBAAgB;AACrE;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,WAAW;AAC7D;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,sDAAsD,KAAK,MAAM,IAAI;;AAErE;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,kDAAkD,KAAK,MAAM,IAAI;;AAEjE;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC9Me;AACf;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,aAAa;AAChE;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gDAAgD,SAAS;;AAEzD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mDAAmD,SAAS;AAC5D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,SAAS;AACT;AACA;AACA,cAAc;AACd;AACA;AACA,SAAS;AACT;AACA,sBAAsB;AACtB;;AAEA;AACA;AACA,mCAAmC;AACnC;AACA,wCAAwC,iBAAiB;AACzD;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;UCnOA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;;;;ACN8C;AACE;;AAEhD,2BAA2B,uDAAa;AACxC,4BAA4B,yDAAc;;AAE1C;AACA;AACA;AACA;;AAEA,IAAI,2DAAa;AACjB,IAAI,6DAAc;AAClB,CAAC","sources":["webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comment_form.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comments.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_handler.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_panel.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reply_forms.js","webpack://django-comments-ink/webpack/bootstrap","webpack://django-comments-ink/webpack/runtime/define property getters","webpack://django-comments-ink/webpack/runtime/hasOwnProperty shorthand","webpack://django-comments-ink/webpack/runtime/make namespace object","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/index.js"],"sourcesContent":["export default class CommentForm {\n constructor(formWrapper) {\n this.formWrapper = formWrapper;\n this.init();\n }\n\n click_on_post(_) { return this.post(\"post\"); }\n\n click_on_preview(_) { return this.post(\"preview\"); }\n\n init() {\n this.formWrapperEl = document.querySelector(this.formWrapper);\n this.formEl = this.formWrapperEl.querySelector(\"form\");\n const post_btn = this.formEl.elements.post;\n const preview_btn = this.formEl.elements.preview;\n post_btn.addEventListener(\"click\", (_) => this.post(\"post\"));\n preview_btn.addEventListener(\"click\", (_) => this.post(\"preview\"));\n // Change the type of the buttons, otherwise the form is submitted.\n post_btn.type = \"button\";\n preview_btn.type = \"button\";\n }\n\n disable_btns(value) {\n this.formEl.elements.post.disabled = value;\n this.formEl.elements.preview.disabled = value;\n }\n\n is_valid() {\n for (const el of this.formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n post(submit_button_name) {\n if (!this.is_valid()) {\n return;\n }\n this.disable_btns(true);\n\n // If the
...
does exist,\n // delete it. If the user clicks again in the \"preview\" button\n // it will be displayed again.\n const preview = this.formWrapperEl.querySelector(\"[data-dci=preview]\");\n if (preview) {\n preview.remove();\n }\n\n const formData = new FormData(this.formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(this.formEl.action, {\n method: 'POST',\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response);\n }\n });\n\n this.disable_btns(false);\n return false; // To prevent calling the action attribute.\n }\n\n async handle_preview_comment_response(response) {\n const data = await response.json();\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n } else if (response.status === 400) {\n this.formEl.innerHTML = data.html;\n }\n }\n\n async handle_post_comment_response(response) {\n const data = await response.json();\n\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.formEl.innerHTML = data.html;\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","import CommentForm from \"./comment_form.js\";\nimport ReplyFormsHandler from \"./reply_forms.js\";\n\n\nfunction init_comments() {\n if (window.dci === null) {\n return;\n }\n\n if (window.dci.page_param === undefined) {\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot) {\n window.dci.page_param = rroot.getAttribute(\"data-page-qs-param\");\n }\n }\n\n window.dci.comment_form = null;\n window.dci.reply_forms_handler = null;\n\n /* ----------------------------------------------\n * Initialize main comment form.\n */\n const qs_cform = \"[data-dci=comment-form]\";\n if (window.dci.comment_form === null &&\n document.querySelector(qs_cform)\n ) {\n window.dci.comment_form = new CommentForm(qs_cform);\n }\n\n /* ----------------------------------------------\n * Initialize reply forms.\n */\n const qs_rform_base = \"[data-dci=reply-form-template]\";\n const qs_rforms = \"[data-dci=reply-form]\";\n if (window.dci.reply_forms_handler === null &&\n document.querySelector(qs_rform_base) &&\n document.querySelectorAll(qs_rforms)\n ) {\n window.dci.reply_forms_handler = new ReplyFormsHandler(qs_rform_base, qs_rforms);\n }\n}\n\nexport { init_comments };\n","import ReactionsHandler from \"./reactions_handler\";\n\nfunction init_reactions() {\n if (window.dci === null) {\n return;\n }\n\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot === null || window.dci === null) {\n return;\n }\n\n window.dci.reactions_handler = null;\n\n /* ----------------------------------------------\n * Initialize reactions_handler, in charge\n * of all reactions popover components.\n */\n if (window.dci.reactions_handler === null) {\n window.dci.reactions_handler = new ReactionsHandler(rroot);\n window.addEventListener(\"beforeunload\", (_) => {\n window.dci.reactions_handler.remove_event_listeners();\n });\n\n }\n}\n\nexport { init_reactions };\n","import ReactionsPanel from \"./reactions_panel\";\n\nexport default class ReactionsHandler {\n constructor(configEl) {\n this.cfg_el = configEl;\n this.is_guest = this.cfg_el.getAttribute(\"data-guest-user\") === \"1\";\n this.login_url = this.init_login_url();\n this.react_url = this.init_react_url();\n\n // Initialize the buttons panels and their components.\n this.links = document.querySelectorAll(\"[data-dci=reactions-panel]\");\n if (this.links.length === 0) {\n throw new Error(\n \"Cannot initialize reactions panel => There are \" +\n \"no elements with [data-dci=reactions-panel].\");\n }\n this.active_visible_panel = 0;\n this.panels_visibility = new Map(); // Keys are 'comment_id'.\n this.event_handlers = [];\n this.add_event_listeners();\n this.listen_to_click_on_links();\n const qs_panel = \"[data-dci=reactions-panel-template]\";\n this.panel_el = document.querySelector(qs_panel);\n if (this.panel_el === undefined) {\n throw new Error(\"Cannot find element with ${qs_panel}.\");\n }\n\n // Create object of class ReactionsPanel in charge of showing and\n // hiding the reactions panel around the clicked 'react' link.\n const opts = {\n panel_el: this.panel_el,\n is_guest: this.is_guest,\n login_url: this.login_url,\n react_url: this.react_url\n };\n this.reactions_panel = new ReactionsPanel(opts);\n }\n\n init_login_url() {\n const url = this.cfg_el.getAttribute(\"data-login-url\");\n if (url === null || url.length === 0) {\n if (this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-login-url] attribute does not exist or is empty.\");\n }\n }\n return url;\n }\n\n init_react_url() {\n const url = this.cfg_el.getAttribute(\"data-react-url\");\n if (url === null || url.length === 0) {\n if (!this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-react-url] attribute does not exist or is empty.\");\n } else {\n console.info(\"Couldn't find the data-react-url attribute, \" +\n \"but the user is anonymous. She has to login first in \" +\n \"order to post comment reactions.\");\n }\n }\n return url;\n }\n\n on_document_click(event) {\n const data_attr = event.target.getAttribute(\"data-dci\");\n if (!data_attr || data_attr !== \"reactions-panel\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n on_document_key_up(event) {\n if (event.key === \"Escape\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n add_event_listeners() {\n const onDocumentClickHandler = this.on_document_click.bind(this);\n const onDocumentKeyUpHandler = this.on_document_key_up.bind(this);\n\n window.document.addEventListener('click', onDocumentClickHandler);\n window.document.addEventListener('keyup', onDocumentKeyUpHandler);\n\n this.event_handlers.push({\n elem: window.document,\n event: 'click',\n handler: this.on_document_click,\n });\n this.event_handlers.push({\n elem: window.document,\n event: 'keyup',\n handler: this.on_document_key_up,\n });\n }\n\n remove_event_listeners() {\n for (const item of this.event_handlers) {\n item.elem.removeEventListener(item.event, item.handler);\n }\n }\n\n listen_to_click_on_links() {\n for (const elem of Array.from(this.links)) {\n const comment_id = elem.getAttribute(\"data-comment\");\n if (comment_id === null) {\n continue;\n }\n const click_handler = this.toggle_reactions_panel(comment_id);\n elem.addEventListener(\"click\", click_handler);\n this.event_handlers.push({\n 'elem': elem,\n 'event': 'click',\n 'handler': click_handler\n });\n this.panels_visibility.set(comment_id, false); // Not visible yet.\n }\n }\n\n toggle_reactions_panel(comment_id) {\n return (event) => {\n event.preventDefault();\n const is_visible = this.panels_visibility.get(comment_id);\n if (!is_visible) {\n this.active_visible_panel = comment_id;\n this.reactions_panel.show(event.target, comment_id);\n } else {\n this.active_visible_panel = 0;\n this.reactions_panel.hide();\n }\n this.panels_visibility.set(comment_id, !is_visible);\n };\n }\n}\n","const enter_delay = 0;\nconst exit_delay = 0;\n\nfunction get_cookie(name) {\n let cookieValue = null;\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n // Does this cookie string begin with the name we want?\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n}\n\nexport default class ReactionsPanel {\n constructor({panel_el, is_guest, login_url, react_url } = opts) {\n this.panel_el = panel_el;\n // this.panel_el.style.zIndex = 1;\n // this.panel_el.style.display = \"block\";\n this.arrow_el = panel_el.querySelector(\".arrow\");\n this.is_guest = is_guest;\n this.login_url = login_url;\n this.react_url = react_url;\n\n // -----------------------------------------------------\n // The panel_title_elem and its content panel_title will\n // change when the user hover the buttons of the panel.\n\n this.panel_title = \"\";\n this.panel_title_elem = this.panel_el.querySelector(\".title\");\n if (this.panel_title_elem) {\n this.panel_title = this.panel_title_elem.textContent;\n }\n\n // -----------------------------------------\n // The comment_id is necessary to know which\n // comment will receive the reaction code.\n\n this.comment_id = 0; // Valid comment_id must be > 0.\n this.next_url = \"\"; // Comment URL to come back after log in.\n\n this.on_react_btn_click = this.on_react_btn_click.bind(this);\n this.on_react_btn_mouseover = this.on_react_btn_mouseover.bind(this);\n this.on_react_btn_mouseout = this.on_react_btn_mouseout.bind(this);\n this.add_event_listeners();\n }\n\n add_event_listeners() {\n const buttons = this.panel_el.querySelectorAll(\"BUTTON\");\n for (const btn of Array.from(buttons)) {\n btn.addEventListener(\"click\", this.on_react_btn_click);\n btn.addEventListener(\"mouseover\", this.on_react_btn_mouseover);\n btn.addEventListener(\"mouseout\", this.on_react_btn_mouseout);\n }\n }\n\n on_react_btn_click(event) {\n if (!this.is_guest) {\n const code = event.target.dataset.code;\n const react_url = this.react_url.replace(\"0\", this.comment_id);\n const formData = new FormData();\n formData.append(\"reaction\", code);\n formData.append(\"csrfmiddlewaretoken\", get_cookie(\"csrftoken\"));\n\n fetch(react_url, {\n method: \"POST\",\n cache: \"no-cache\",\n credentials: \"same-origin\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => this.handle_reactions_response(response));\n } else {\n window.location.href = `${this.login_url}?next=${this.next_url}`;\n }\n }\n\n async handle_reactions_response(response) {\n const data = await response.json();\n if (response.status === 200 || response.status === 201) {\n const cm_reactions_qs = `#cm-reactions-${this.comment_id}`;\n const cm_reactions_el = document.querySelector(cm_reactions_qs);\n if (cm_reactions_el) {\n cm_reactions_el.innerHTML = data.html;\n }\n } else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment reaction could not \" +\n \"be processed. Please, reload the page and try again.\"\n );\n }\n }\n\n on_react_btn_mouseover(event) {\n if (this.panel_title_elem) {\n this.panel_title_elem.textContent = event.target.dataset.title;\n }\n }\n\n on_react_btn_mouseout(_) {\n this.panel_title_elem.textContent = this.panel_title;\n }\n\n set_position(trigger_elem) {\n this.panel_el.style.display = \"block\";\n\n const panel_elem_coords = this.get_absolute_coords(this.panel_el);\n const trigger_elem_coords = this.get_absolute_coords(trigger_elem);\n\n const panel_elem_width = panel_elem_coords.width;\n const panel_elem_height = panel_elem_coords.height;\n const panel_elem_top = panel_elem_coords.top;\n const panel_elem_left = panel_elem_coords.left;\n\n const trigger_elem_width = trigger_elem_coords.width;\n const trigger_elem_top = trigger_elem_coords.top;\n const trigger_elem_left = trigger_elem_coords.left;\n\n const top_diff = trigger_elem_top - panel_elem_top;\n const left_diff = trigger_elem_left - panel_elem_left;\n\n // This group of const values can be hardcoded somewhere else.\n // const position = \"auto\";\n const margin = 8;\n\n const width_center = trigger_elem_width / 2 - panel_elem_width / 2;\n\n const left = left_diff + width_center;\n const top = top_diff - panel_elem_height - margin;\n const from_top = top + 10;\n\n this.panel_el.dataset.fromLeft = left;\n this.panel_el.dataset.fromTop = from_top;\n this.panel_el.dataset.left = left;\n this.panel_el.dataset.top = top;\n\n // Arrow.\n if (this.arrow_el) {\n let arrow_left = 0;\n const full_left = left + panel_elem_left;\n const t_width_center = trigger_elem_width / 2 + trigger_elem_left;\n arrow_left = t_width_center - full_left;\n const transform_text = `translate3d(${arrow_left}px, 0px, 0)`;\n this.arrow_el.style.transform = transform_text;\n }\n }\n\n hide() {\n clearTimeout(this.enter_delay_timeout);\n\n this.exit_delat_timeout = setTimeout(() => {\n if (this.panel_el) {\n const left = this.panel_el.dataset.fromLeft;\n const top = this.panel_el.dataset.fromTop;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 0;\n this.panel_el.style.display = \"none\";\n this.panel_el.style.zIndex = 0;\n }\n }, exit_delay);\n }\n\n show(trigger_elem, comment_id) {\n this.comment_id = comment_id;\n this.next_url = trigger_elem.dataset.loginNext || \"\";\n this.panel_el.style.transform = \"none\";\n this.set_position(trigger_elem);\n\n this.enter_delay_timeout = setTimeout(() => {\n const left = this.panel_el.dataset.left;\n const top = this.panel_el.dataset.top;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.zIndex = 1;\n this.panel_el.style.display = \"block\";\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 1;\n }, enter_delay);\n }\n\n get_absolute_coords(elem) {\n if (!elem) {\n return;\n }\n\n const box = elem.getBoundingClientRect();\n const page_x = window.pageXOffset;\n const page_y = window.pageYOffset;\n\n return {\n width: box.width,\n height: box.height,\n top: box.top + page_y,\n right: box.right + page_x,\n bottom: box.bottom + page_y,\n left: box.left + page_x,\n };\n }\n}\n","export default class ReplyFormsHandler {\n constructor(qsReplyFormBase, qsReplyForms) {\n this.replyFormBase = document.querySelector(qsReplyFormBase);\n this.replyMap = new Map();\n\n const cpage_field = window.dci.page_param || \"cpage\";\n\n for (const elem of document.querySelectorAll(qsReplyForms)) {\n // Extract the reply_to value from the current reply_form.\n // Also, it if does exist, extract the comment's page number too.\n // Then replace the content of elem with a copy of\n // this.replyFormBase and update the fields reply_to\n // and comment's page number.\n const rFormEl = elem.querySelector(\"form\");\n if (rFormEl === null) {\n console.error(\n `Could not find a reply form within one of ` +\n `the elements retrieved with ${qsReplyForms}.`\n );\n return;\n }\n\n const reply_to = rFormEl.elements.reply_to.value;\n const cpage = rFormEl.elements[cpage_field]\n ? rFormEl.elements[cpage_field].value\n : null;\n\n const section = this.replyFormBase.cloneNode(true);\n section.dataset.dci = `reply-form-${reply_to}`;\n\n // Update fields reply_to and cpage..\n const newForm = section.querySelector(\"form\");\n newForm.elements.reply_to.value = reply_to;\n if (cpage) {\n newForm.elements[cpage_field].value = cpage;\n }\n\n const elemParent = elem.parentNode;\n elem.replaceWith(section);\n this.init(reply_to);\n this.replyMap.set(reply_to, elemParent);\n }\n }\n\n init(reply_to, is_active) {\n const qs_section = `[data-dci=reply-form-${reply_to}]`;\n const section = document.querySelector(qs_section);\n\n // Modify the form (update fields, add event listeners).\n const newForm = section.querySelector(\"form\");\n const post_btn = newForm.elements.post;\n post_btn.addEventListener(\"click\", this.send_clicked(reply_to));\n const preview_btn = newForm.elements.preview;\n preview_btn.addEventListener(\"click\", this.preview_clicked(reply_to));\n const cancel_btn = newForm.elements.cancel;\n cancel_btn.addEventListener(\"click\", this.cancel_clicked(reply_to));\n newForm.style.display = \"none\";\n\n // Attach event listener to textarea.\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const ta = divta.querySelector(\"textarea\");\n ta.addEventListener(\"focus\", this.textarea_focus(reply_to));\n\n // If is_active is true, hide the textarea and display the form.\n if (is_active === true) {\n section.classList.add(\"active\");\n divta.style.display = \"none\";\n newForm.style = \"\";\n newForm.elements.comment.focus();\n }\n }\n\n get_map_item(reply_to) {\n const item = this.replyMap.get(reply_to);\n if (item === undefined) {\n const msg = `replyMap doesn't have a key ${reply_to}`;\n console.error(msg);\n throw msg;\n }\n return item;\n }\n\n disable_buttons(formEl, value) {\n formEl.elements.post.disabled = value;\n formEl.elements.preview.disabled = value;\n }\n\n is_valid(formEl) {\n for (const el of formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n textarea_focus(reply_to) {\n // Display the comment form and hide the text area.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n section.classList.toggle(\"active\");\n divta.style.display = \"none\";\n form.style = \"\";\n form.elements.comment.focus();\n };\n }\n\n cancel_clicked(reply_to) {\n // Display the text area and hide the comment form.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const comment_value = form.elements.comment.value;\n divta.querySelector(\"textarea\").value = comment_value;\n section.classList.toggle(\"active\");\n form.style.display = \"none\";\n divta.style = \"\";\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n };\n }\n\n preview_clicked(reply_to) {\n return (_) => {\n this.post(\"preview\", reply_to);\n };\n }\n\n send_clicked(reply_to) {\n return (_) => {\n this.post(\"post\", reply_to);\n };\n }\n\n post(submit_button_name, reply_to) {\n const item = this.get_map_item(reply_to);\n const formEl = item.querySelector(\"form\");\n\n if (!this.is_valid(formEl)) {\n return;\n }\n\n this.disable_buttons(formEl, true);\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n\n const formData = new FormData(formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(formEl.action, {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response, reply_to);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response, reply_to);\n }\n });\n this.disable_buttons(formEl, false);\n return false; // To prevent calling the action attribute.\n }\n\n handle_http_200(item, data, reply_to) {\n item.innerHTML = data.html;\n this.init(reply_to, true); // 2nd param: is_active = true.\n if (data.field_focus) {\n item.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n\n handle_http_201_202_400(item, data) {\n const form = item.querySelector(\"form\");\n form.innerHTML = data.html;\n }\n\n async handle_preview_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n } else if (response.status === 400) {\n this.handle_http_201_202_400(item, data);\n }\n }\n\n async handle_post_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.handle_http_201_202_400(item, data);\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { init_comments } from \"./comments.js\";\nimport { init_reactions } from \"./reactions.js\";\n\nwindow.dci.init_comments = init_comments;\nwindow.dci.init_reactions = init_reactions;\n\nwindow.addEventListener(\"DOMContentLoaded\", (_) => {\n if (window.dci === null) {\n return;\n }\n\n init_comments();\n init_reactions();\n});\n"],"names":[],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"dci-0.0.2.js","mappings":";;;;;;;;;;;;;;AAAe;AACf;AACA;AACA;AACA;;AAEA,uBAAuB;;AAEvB,0BAA0B;;AAE1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,SAAS;AACT;AACA;AACA,cAAc;AACd;AACA;AACA,SAAS;;AAET;AACA,sBAAsB;AACtB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,iBAAiB;AACpE;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,mDAAmD,iBAAiB;AACpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AC/G4C;AACK;;;AAGjD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC,wDAAW;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,uDAAiB;AAC9D;AACA;;AAEyB;;;;;;;;;;;;;;;;AC1C0B;;AAEnD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,2CAA2C,0DAAgB;AAC3D;AACA;AACA,SAAS;;AAET;AACA;;AAE0B;;;;;;;;;;;;;;;;AC3BqB;;AAEhC;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,SAAS;AACjE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,wDAAc;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,2DAA2D;AAC3D;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC7IA;AACA;;AAEA;AACA;AACA;AACA,gDAAgD;AAChD,wBAAwB,oBAAoB;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEe;AACf,iBAAiB,2CAA2C;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,6BAA6B;AAC7B,4BAA4B;;AAE5B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,aAAa;AACb,UAAU;AACV,sCAAsC,eAAe,QAAQ,cAAc;AAC3E;AACA;;AAEA;AACA;AACA;AACA,qDAAqD,gBAAgB;AACrE;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,WAAW;AAC7D;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,sDAAsD,KAAK,MAAM,IAAI;;AAErE;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,kDAAkD,KAAK,MAAM,IAAI;;AAEjE;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC9Me;AACf;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,aAAa;AAChE;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,gDAAgD,SAAS;;AAEzD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mDAAmD,SAAS;AAC5D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,SAAS;AACT;AACA;AACA,cAAc;AACd;AACA;AACA,SAAS;AACT;AACA,sBAAsB;AACtB;;AAEA;AACA;AACA,mCAAmC;AACnC;AACA,wCAAwC,iBAAiB;AACzD;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;UCnOA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;;;;ACN8C;AACE;;AAEhD,2BAA2B,uDAAa;AACxC,4BAA4B,yDAAc;;AAE1C;AACA;AACA;AACA;;AAEA,IAAI,2DAAa;AACjB,IAAI,6DAAc;AAClB,CAAC","sources":["webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comment_form.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comments.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_handler.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_panel.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reply_forms.js","webpack://django-comments-ink/webpack/bootstrap","webpack://django-comments-ink/webpack/runtime/define property getters","webpack://django-comments-ink/webpack/runtime/hasOwnProperty shorthand","webpack://django-comments-ink/webpack/runtime/make namespace object","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/index.js"],"sourcesContent":["export default class CommentForm {\n constructor(formWrapper) {\n this.formWrapper = formWrapper;\n this.init();\n }\n\n click_on_post(_) { return this.post(\"post\"); }\n\n click_on_preview(_) { return this.post(\"preview\"); }\n\n init() {\n this.formWrapperEl = document.querySelector(this.formWrapper);\n this.formEl = this.formWrapperEl.querySelector(\"form\");\n const post_btn = this.formEl.elements.post;\n const preview_btn = this.formEl.elements.preview;\n post_btn.addEventListener(\"click\", (_) => this.post(\"post\"));\n preview_btn.addEventListener(\"click\", (_) => this.post(\"preview\"));\n // Change the type of the buttons, otherwise the form is submitted.\n post_btn.type = \"button\";\n preview_btn.type = \"button\";\n }\n\n disable_btns(value) {\n this.formEl.elements.post.disabled = value;\n this.formEl.elements.preview.disabled = value;\n }\n\n is_valid() {\n for (const el of this.formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n post(submit_button_name) {\n if (!this.is_valid()) {\n return;\n }\n this.disable_btns(true);\n\n // If the
...
does exist,\n // delete it. If the user clicks again in the \"preview\" button\n // it will be displayed again.\n const preview = this.formWrapperEl.querySelector(\"[data-dci=preview]\");\n if (preview) {\n preview.remove();\n }\n\n const formData = new FormData(this.formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(this.formEl.action, {\n method: 'POST',\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response);\n }\n });\n\n this.disable_btns(false);\n return false; // To prevent calling the action attribute.\n }\n\n async handle_preview_comment_response(response) {\n const data = await response.json();\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n } else if (response.status === 400) {\n this.formEl.innerHTML = data.html;\n }\n }\n\n async handle_post_comment_response(response) {\n const data = await response.json();\n\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.formEl.innerHTML = data.html;\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","import CommentForm from \"./comment_form.js\";\nimport ReplyFormsHandler from \"./reply_forms.js\";\n\n\nfunction init_comments() {\n if (window.dci === null) {\n return;\n }\n\n if (window.dci.page_param === undefined) {\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot) {\n window.dci.page_param = rroot.getAttribute(\"data-page-qs-param\");\n }\n }\n\n window.dci.comment_form = null;\n window.dci.reply_forms_handler = null;\n\n /* ----------------------------------------------\n * Initialize main comment form.\n */\n const qs_cform = \"[data-dci=comment-form]\";\n if (window.dci.comment_form === null &&\n document.querySelector(qs_cform)\n ) {\n window.dci.comment_form = new CommentForm(qs_cform);\n }\n\n /* ----------------------------------------------\n * Initialize reply forms.\n */\n const qs_rform_base = \"[data-dci=reply-form-template]\";\n const qs_rforms = \"[data-dci=reply-form]\";\n if (window.dci.reply_forms_handler === null &&\n document.querySelector(qs_rform_base) &&\n document.querySelectorAll(qs_rforms)\n ) {\n window.dci.reply_forms_handler = new ReplyFormsHandler(qs_rform_base, qs_rforms);\n }\n}\n\nexport { init_comments };\n","import ReactionsHandler from \"./reactions_handler\";\n\nfunction init_reactions() {\n if (window.dci === null) {\n return;\n }\n\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot === null || window.dci === null) {\n return;\n }\n\n window.dci.reactions_handler = null;\n\n /* ----------------------------------------------\n * Initialize reactions_handler, in charge\n * of all reactions popover components.\n */\n if (window.dci.reactions_handler === null) {\n window.dci.reactions_handler = new ReactionsHandler(rroot);\n window.addEventListener(\"beforeunload\", (_) => {\n window.dci.reactions_handler.remove_event_listeners();\n });\n\n }\n}\n\nexport { init_reactions };\n","import ReactionsPanel from \"./reactions_panel\";\n\nexport default class ReactionsHandler {\n constructor(configEl) {\n this.cfg_el = configEl;\n this.is_guest = this.cfg_el.getAttribute(\"data-guest-user\") === \"1\";\n this.login_url = this.init_login_url();\n this.react_url = this.init_react_url();\n\n // Initialize the buttons panels and their components.\n this.links = document.querySelectorAll(\"[data-dci=reactions-panel]\");\n if (this.links.length === 0) {\n throw new Error(\n \"Cannot initialize reactions panel => There are \" +\n \"no elements with [data-dci=reactions-panel].\");\n }\n this.active_visible_panel = 0;\n this.panels_visibility = new Map(); // Keys are 'comment_id'.\n this.event_handlers = [];\n this.add_event_listeners();\n this.listen_to_click_on_links();\n const qs_panel = \"[data-dci=reactions-panel-template]\";\n this.panel_el = document.querySelector(qs_panel);\n if (this.panel_el === undefined) {\n throw new Error(\"Cannot find element with ${qs_panel}.\");\n }\n\n // Create object of class ReactionsPanel in charge of showing and\n // hiding the reactions panel around the clicked 'react' link.\n const opts = {\n panel_el: this.panel_el,\n is_guest: this.is_guest,\n login_url: this.login_url,\n react_url: this.react_url\n };\n this.reactions_panel = new ReactionsPanel(opts);\n }\n\n init_login_url() {\n const url = this.cfg_el.getAttribute(\"data-login-url\");\n if (url === null || url.length === 0) {\n if (this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-login-url] attribute does not exist or is empty.\");\n }\n }\n return url;\n }\n\n init_react_url() {\n const url = this.cfg_el.getAttribute(\"data-react-url\");\n if (url === null || url.length === 0) {\n if (!this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-react-url] attribute does not exist or is empty.\");\n } else {\n console.info(\"Couldn't find the data-react-url attribute, \" +\n \"but the user is anonymous. She has to login first in \" +\n \"order to post comment reactions.\");\n }\n }\n return url;\n }\n\n on_document_click(event) {\n const data_attr = event.target.getAttribute(\"data-dci\");\n if (!data_attr || data_attr !== \"reactions-panel\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n on_document_key_up(event) {\n if (event.key === \"Escape\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n add_event_listeners() {\n const onDocumentClickHandler = this.on_document_click.bind(this);\n const onDocumentKeyUpHandler = this.on_document_key_up.bind(this);\n\n window.document.addEventListener('click', onDocumentClickHandler);\n window.document.addEventListener('keyup', onDocumentKeyUpHandler);\n\n this.event_handlers.push({\n elem: window.document,\n event: 'click',\n handler: this.on_document_click,\n });\n this.event_handlers.push({\n elem: window.document,\n event: 'keyup',\n handler: this.on_document_key_up,\n });\n }\n\n remove_event_listeners() {\n for (const item of this.event_handlers) {\n item.elem.removeEventListener(item.event, item.handler);\n }\n }\n\n listen_to_click_on_links() {\n for (const elem of Array.from(this.links)) {\n const comment_id = elem.getAttribute(\"data-comment\");\n if (comment_id === null) {\n continue;\n }\n const click_handler = this.toggle_reactions_panel(comment_id);\n elem.addEventListener(\"click\", click_handler);\n this.event_handlers.push({\n 'elem': elem,\n 'event': 'click',\n 'handler': click_handler\n });\n this.panels_visibility.set(comment_id, false); // Not visible yet.\n }\n }\n\n toggle_reactions_panel(comment_id) {\n return (event) => {\n event.preventDefault();\n const is_visible = this.panels_visibility.get(comment_id);\n if (!is_visible) {\n this.active_visible_panel = comment_id;\n this.reactions_panel.show(event.target, comment_id);\n } else {\n this.active_visible_panel = 0;\n this.reactions_panel.hide();\n }\n this.panels_visibility.set(comment_id, !is_visible);\n };\n }\n}\n","const enter_delay = 0;\nconst exit_delay = 0;\n\nfunction get_cookie(name) {\n let cookieValue = null;\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n // Does this cookie string begin with the name we want?\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n}\n\nexport default class ReactionsPanel {\n constructor({panel_el, is_guest, login_url, react_url } = opts) {\n this.panel_el = panel_el;\n // this.panel_el.style.zIndex = 1;\n // this.panel_el.style.display = \"block\";\n this.arrow_el = panel_el.querySelector(\".arrow\");\n this.is_guest = is_guest;\n this.login_url = login_url;\n this.react_url = react_url;\n\n // -----------------------------------------------------\n // The panel_title_elem and its content panel_title will\n // change when the user hover the buttons of the panel.\n\n this.panel_title = \"\";\n this.panel_title_elem = this.panel_el.querySelector(\".title\");\n if (this.panel_title_elem) {\n this.panel_title = this.panel_title_elem.textContent;\n }\n\n // -----------------------------------------\n // The comment_id is necessary to know which\n // comment will receive the reaction code.\n\n this.comment_id = 0; // Valid comment_id must be > 0.\n this.next_url = \"\"; // Comment URL to come back after log in.\n\n this.on_react_btn_click = this.on_react_btn_click.bind(this);\n this.on_react_btn_mouseover = this.on_react_btn_mouseover.bind(this);\n this.on_react_btn_mouseout = this.on_react_btn_mouseout.bind(this);\n this.add_event_listeners();\n }\n\n add_event_listeners() {\n const buttons = this.panel_el.querySelectorAll(\"BUTTON\");\n for (const btn of Array.from(buttons)) {\n btn.addEventListener(\"click\", this.on_react_btn_click);\n btn.addEventListener(\"mouseover\", this.on_react_btn_mouseover);\n btn.addEventListener(\"mouseout\", this.on_react_btn_mouseout);\n }\n }\n\n on_react_btn_click(event) {\n if (!this.is_guest) {\n const code = event.target.dataset.code;\n const react_url = this.react_url.replace(\"0\", this.comment_id);\n const formData = new FormData();\n formData.append(\"reaction\", code);\n formData.append(\"csrfmiddlewaretoken\", get_cookie(\"csrftoken\"));\n\n fetch(react_url, {\n method: \"POST\",\n cache: \"no-cache\",\n credentials: \"same-origin\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => this.handle_reactions_response(response));\n } else {\n window.location.href = `${this.login_url}?next=${this.next_url}`;\n }\n }\n\n async handle_reactions_response(response) {\n const data = await response.json();\n if (response.status === 200 || response.status === 201) {\n const cm_reactions_qs = `#cm-reactions-${this.comment_id}`;\n const cm_reactions_el = document.querySelector(cm_reactions_qs);\n if (cm_reactions_el) {\n cm_reactions_el.innerHTML = data.html;\n }\n } else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment reaction could not \" +\n \"be processed. Please, reload the page and try again.\"\n );\n }\n }\n\n on_react_btn_mouseover(event) {\n if (this.panel_title_elem) {\n this.panel_title_elem.textContent = event.target.dataset.title;\n }\n }\n\n on_react_btn_mouseout(_) {\n this.panel_title_elem.textContent = this.panel_title;\n }\n\n set_position(trigger_elem) {\n this.panel_el.style.display = \"block\";\n\n const panel_elem_coords = this.get_absolute_coords(this.panel_el);\n const trigger_elem_coords = this.get_absolute_coords(trigger_elem);\n\n const panel_elem_width = panel_elem_coords.width;\n const panel_elem_height = panel_elem_coords.height;\n const panel_elem_top = panel_elem_coords.top;\n const panel_elem_left = panel_elem_coords.left;\n\n const trigger_elem_width = trigger_elem_coords.width;\n const trigger_elem_top = trigger_elem_coords.top;\n const trigger_elem_left = trigger_elem_coords.left;\n\n const top_diff = trigger_elem_top - panel_elem_top;\n const left_diff = trigger_elem_left - panel_elem_left;\n\n // This group of const values can be hardcoded somewhere else.\n // const position = \"auto\";\n const margin = 8;\n\n const width_center = trigger_elem_width / 2 - panel_elem_width / 2;\n\n const left = left_diff + width_center;\n const top = top_diff - panel_elem_height - margin;\n const from_top = top + 10;\n\n this.panel_el.dataset.fromLeft = left;\n this.panel_el.dataset.fromTop = from_top;\n this.panel_el.dataset.left = left;\n this.panel_el.dataset.top = top;\n\n // Arrow.\n if (this.arrow_el) {\n let arrow_left = 0;\n const full_left = left + panel_elem_left;\n const t_width_center = trigger_elem_width / 2 + trigger_elem_left;\n arrow_left = t_width_center - full_left;\n const transform_text = `translate3d(${arrow_left}px, 0px, 0)`;\n this.arrow_el.style.transform = transform_text;\n }\n }\n\n hide() {\n clearTimeout(this.enter_delay_timeout);\n\n this.exit_delat_timeout = setTimeout(() => {\n if (this.panel_el) {\n const left = this.panel_el.dataset.fromLeft;\n const top = this.panel_el.dataset.fromTop;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 0;\n this.panel_el.style.display = \"none\";\n this.panel_el.style.zIndex = 0;\n }\n }, exit_delay);\n }\n\n show(trigger_elem, comment_id) {\n this.comment_id = comment_id;\n this.next_url = trigger_elem.dataset.loginNext || \"\";\n this.panel_el.style.transform = \"none\";\n this.set_position(trigger_elem);\n\n this.enter_delay_timeout = setTimeout(() => {\n const left = this.panel_el.dataset.left;\n const top = this.panel_el.dataset.top;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.zIndex = 1;\n this.panel_el.style.display = \"block\";\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 1;\n }, enter_delay);\n }\n\n get_absolute_coords(elem) {\n if (!elem) {\n return;\n }\n\n const box = elem.getBoundingClientRect();\n const page_x = window.pageXOffset;\n const page_y = window.pageYOffset;\n\n return {\n width: box.width,\n height: box.height,\n top: box.top + page_y,\n right: box.right + page_x,\n bottom: box.bottom + page_y,\n left: box.left + page_x,\n };\n }\n}\n","export default class ReplyFormsHandler {\n constructor(qsReplyFormBase, qsReplyForms) {\n this.replyFormBase = document.querySelector(qsReplyFormBase);\n this.replyMap = new Map();\n\n const cpage_field = window.dci.page_param || \"cpage\";\n\n for (const elem of document.querySelectorAll(qsReplyForms)) {\n // Extract the reply_to value from the current reply_form.\n // Also, it if does exist, extract the comment's page number too.\n // Then replace the content of elem with a copy of\n // this.replyFormBase and update the fields reply_to\n // and comment's page number.\n const rFormEl = elem.querySelector(\"form\");\n if (rFormEl === null) {\n console.error(\n `Could not find a reply form within one of ` +\n `the elements retrieved with ${qsReplyForms}.`\n );\n return;\n }\n\n const reply_to = rFormEl.elements.reply_to.value;\n const cpage = rFormEl.elements[cpage_field]\n ? rFormEl.elements[cpage_field].value\n : null;\n\n const section = this.replyFormBase.cloneNode(true);\n section.dataset.dci = `reply-form-${reply_to}`;\n\n // Update fields reply_to and cpage..\n const newForm = section.querySelector(\"form\");\n newForm.elements.reply_to.value = reply_to;\n if (cpage) {\n newForm.elements[cpage_field].value = cpage;\n }\n\n const elemParent = elem.parentNode;\n elem.replaceWith(section);\n this.init(reply_to);\n this.replyMap.set(reply_to, elemParent);\n }\n }\n\n init(reply_to, is_active) {\n const qs_section = `[data-dci=reply-form-${reply_to}]`;\n const section = document.querySelector(qs_section);\n\n // Modify the form (update fields, add event listeners).\n const newForm = section.querySelector(\"form\");\n const post_btn = newForm.elements.post;\n post_btn.addEventListener(\"click\", this.send_clicked(reply_to));\n const preview_btn = newForm.elements.preview;\n preview_btn.addEventListener(\"click\", this.preview_clicked(reply_to));\n const cancel_btn = newForm.elements.cancel;\n cancel_btn.addEventListener(\"click\", this.cancel_clicked(reply_to));\n newForm.style.display = \"none\";\n\n // Attach event listener to textarea.\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const ta = divta.querySelector(\"textarea\");\n ta.addEventListener(\"focus\", this.textarea_focus(reply_to));\n\n // If is_active is true, hide the textarea and display the form.\n if (is_active === true) {\n section.classList.add(\"active\");\n divta.style.display = \"none\";\n newForm.style = \"\";\n newForm.elements.comment.focus();\n }\n }\n\n get_map_item(reply_to) {\n const item = this.replyMap.get(reply_to);\n if (item === undefined) {\n const msg = `replyMap doesn't have a key ${reply_to}`;\n console.error(msg);\n throw msg;\n }\n return item;\n }\n\n disable_buttons(formEl, value) {\n formEl.elements.post.disabled = value;\n formEl.elements.preview.disabled = value;\n }\n\n is_valid(formEl) {\n for (const el of formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n textarea_focus(reply_to) {\n // Display the comment form and hide the text area.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n section.classList.toggle(\"active\");\n divta.style.display = \"none\";\n form.style = \"\";\n form.elements.comment.focus();\n };\n }\n\n cancel_clicked(reply_to) {\n // Display the text area and hide the comment form.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const comment_value = form.elements.comment.value;\n divta.querySelector(\"textarea\").value = comment_value;\n section.classList.toggle(\"active\");\n form.style.display = \"none\";\n divta.style = \"\";\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n };\n }\n\n preview_clicked(reply_to) {\n return (_) => {\n this.post(\"preview\", reply_to);\n };\n }\n\n send_clicked(reply_to) {\n return (_) => {\n this.post(\"post\", reply_to);\n };\n }\n\n post(submit_button_name, reply_to) {\n const item = this.get_map_item(reply_to);\n const formEl = item.querySelector(\"form\");\n\n if (!this.is_valid(formEl)) {\n return;\n }\n\n this.disable_buttons(formEl, true);\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n\n const formData = new FormData(formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(formEl.action, {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response, reply_to);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response, reply_to);\n }\n });\n this.disable_buttons(formEl, false);\n return false; // To prevent calling the action attribute.\n }\n\n handle_http_200(item, data, reply_to) {\n item.innerHTML = data.html;\n this.init(reply_to, true); // 2nd param: is_active = true.\n if (data.field_focus) {\n item.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n\n handle_http_201_202_400(item, data) {\n const form = item.querySelector(\"form\");\n form.innerHTML = data.html;\n }\n\n async handle_preview_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n } else if (response.status === 400) {\n this.handle_http_201_202_400(item, data);\n }\n }\n\n async handle_post_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.handle_http_201_202_400(item, data);\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { init_comments } from \"./comments.js\";\nimport { init_reactions } from \"./reactions.js\";\n\nwindow.dci.init_comments = init_comments;\nwindow.dci.init_reactions = init_reactions;\n\nwindow.addEventListener(\"DOMContentLoaded\", (_) => {\n if (window.dci === null) {\n return;\n }\n\n init_comments();\n init_reactions();\n});\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.min.js b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.min.js similarity index 99% rename from django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.min.js rename to django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.min.js index a38099c..cf487b6 100644 --- a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.min.js +++ b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.min.js @@ -1,2 +1,2 @@ (()=>{"use strict";class CommentForm{constructor(e){this.formWrapper=e,this.init()}click_on_post(e){return this.post("post")}click_on_preview(e){return this.post("preview")}init(){this.formWrapperEl=document.querySelector(this.formWrapper),this.formEl=this.formWrapperEl.querySelector("form");const e=this.formEl.elements.post,t=this.formEl.elements.preview;e.addEventListener("click",(e=>this.post("post"))),t.addEventListener("click",(e=>this.post("preview"))),e.type="button",t.type="button"}disable_btns(e){this.formEl.elements.post.disabled=e,this.formEl.elements.preview.disabled=e}is_valid(){for(const e of this.formEl.querySelectorAll("[required]"))if(!e.reportValidity())return e.focus(),!1;return!0}post(e){if(!this.is_valid())return;this.disable_btns(!0);const t=this.formWrapperEl.querySelector("[data-dci=preview]");t&&t.remove();const i=new FormData(this.formEl);return void 0!==e&&i.append(e,1),fetch(this.formEl.action,{method:"POST",headers:{"X-Requested-With":"XMLHttpRequest"},body:i}).then((t=>{"preview"===e?this.handle_preview_comment_response(t):"post"===e&&this.handle_post_comment_response(t)})),this.disable_btns(!1),!1}async handle_preview_comment_response(e){const t=await e.json();200===e.status?(this.formWrapperEl.innerHTML=t.html,this.init(),t.field_focus&&this.formEl.querySelector(`[name=${t.field_focus}]`).focus()):400===e.status&&(this.formEl.innerHTML=t.html)}async handle_post_comment_response(e){const t=await e.json();200===e.status?(this.formWrapperEl.innerHTML=t.html,this.init(),t.field_focus&&this.formEl.querySelector(`[name=${t.field_focus}]`).focus()):201===e.status||202===e.status||400===e.status?this.formEl.innerHTML=t.html:e.status>400&&alert("Something went wrong and your comment could not be processed. Please, reload the page and try again.")}}class ReplyFormsHandler{constructor(e,t){this.replyFormBase=document.querySelector(e),this.replyMap=new Map;const i=window.dci.page_param||"cpage";for(const n of document.querySelectorAll(t)){const e=n.querySelector("form");if(null===e)return void console.error(`Could not find a reply form within one of the elements retrieved with ${t}.`);const s=e.elements.reply_to.value,o=e.elements[i]?e.elements[i].value:null,l=this.replyFormBase.cloneNode(!0);l.dataset.dci=`reply-form-${s}`;const r=l.querySelector("form");r.elements.reply_to.value=s,o&&(r.elements[i].value=o);const a=n.parentNode;n.replaceWith(l),this.init(s),this.replyMap.set(s,a)}}init(e,t){const i=`[data-dci=reply-form-${e}]`,n=document.querySelector(i),s=n.querySelector("form");s.elements.post.addEventListener("click",this.send_clicked(e));s.elements.preview.addEventListener("click",this.preview_clicked(e));s.elements.cancel.addEventListener("click",this.cancel_clicked(e)),s.style.display="none";const o=n.querySelector("[data-dci=reply-textarea]");o.querySelector("textarea").addEventListener("focus",this.textarea_focus(e)),!0===t&&(n.classList.add("active"),o.style.display="none",s.style="",s.elements.comment.focus())}get_map_item(e){const t=this.replyMap.get(e);if(void 0===t){const t=`replyMap doesn't have a key ${e}`;throw console.error(t),t}return t}disable_buttons(e,t){e.elements.post.disabled=t,e.elements.preview.disabled=t}is_valid(e){for(const t of e.querySelectorAll("[required]"))if(!t.reportValidity())return t.focus(),!1;return!0}textarea_focus(e){return t=>{const i=this.get_map_item(e),n=`[data-dci=reply-form-${e}`,s=i.querySelector(n),o=s.querySelector("form"),l=s.querySelector("[data-dci=reply-textarea]");s.classList.toggle("active"),l.style.display="none",o.style="",o.elements.comment.focus()}}cancel_clicked(e){return t=>{const i=this.get_map_item(e),n=`[data-dci=reply-form-${e}`,s=i.querySelector(n),o=s.querySelector("form"),l=s.querySelector("[data-dci=reply-textarea]"),r=o.elements.comment.value;l.querySelector("textarea").value=r,s.classList.toggle("active"),o.style.display="none",l.style="";const a=i.querySelector("[data-dci=preview]");a&&a.remove()}}preview_clicked(e){return t=>{this.post("preview",e)}}send_clicked(e){return t=>{this.post("post",e)}}post(e,t){const i=this.get_map_item(t),n=i.querySelector("form");if(!this.is_valid(n))return;this.disable_buttons(n,!0);const s=i.querySelector("[data-dci=preview]");s&&s.remove();const o=new FormData(n);return void 0!==e&&o.append(e,1),fetch(n.action,{method:"POST",headers:{"X-Requested-With":"XMLHttpRequest"},body:o}).then((i=>{"preview"===e?this.handle_preview_comment_response(i,t):"post"===e&&this.handle_post_comment_response(i,t)})),this.disable_buttons(n,!1),!1}handle_http_200(e,t,i){e.innerHTML=t.html,this.init(i,!0),t.field_focus&&e.querySelector(`[name=${t.field_focus}]`).focus()}handle_http_201_202_400(e,t){e.querySelector("form").innerHTML=t.html}async handle_preview_comment_response(e,t){const i=this.get_map_item(t),n=await e.json();200===e.status?this.handle_http_200(i,n,t):400===e.status&&this.handle_http_201_202_400(i,n)}async handle_post_comment_response(e,t){const i=this.get_map_item(t),n=await e.json();200===e.status?this.handle_http_200(i,n,t):201===e.status||202===e.status||400===e.status?this.handle_http_201_202_400(i,n):e.status>400&&alert("Something went wrong and your comment could not be processed. Please, reload the page and try again.")}}function init_comments(){if(null===window.dci)return;if(void 0===window.dci.page_param){const e=document.querySelector("[data-dci=config]");e&&(window.dci.page_param=e.getAttribute("data-page-qs-param"))}window.dci.comment_form=null,window.dci.reply_forms_handler=null;const e="[data-dci=comment-form]";null===window.dci.comment_form&&document.querySelector(e)&&(window.dci.comment_form=new CommentForm(e));const t="[data-dci=reply-form-template]",i="[data-dci=reply-form]";null===window.dci.reply_forms_handler&&document.querySelector(t)&&document.querySelectorAll(i)&&(window.dci.reply_forms_handler=new ReplyFormsHandler(t,i))}class ReactionsPanel{constructor({panel_el:e,is_guest:t,login_url:i,react_url:n}=opts){this.panel_el=e,this.arrow_el=e.querySelector(".arrow"),this.is_guest=t,this.login_url=i,this.react_url=n,this.panel_title="",this.panel_title_elem=this.panel_el.querySelector(".title"),this.panel_title_elem&&(this.panel_title=this.panel_title_elem.textContent),this.comment_id=0,this.next_url="",this.on_react_btn_click=this.on_react_btn_click.bind(this),this.on_react_btn_mouseover=this.on_react_btn_mouseover.bind(this),this.on_react_btn_mouseout=this.on_react_btn_mouseout.bind(this),this.add_event_listeners()}add_event_listeners(){const e=this.panel_el.querySelectorAll("BUTTON");for(const t of Array.from(e))t.addEventListener("click",this.on_react_btn_click),t.addEventListener("mouseover",this.on_react_btn_mouseover),t.addEventListener("mouseout",this.on_react_btn_mouseout)}on_react_btn_click(e){if(this.is_guest)window.location.href=`${this.login_url}?next=${this.next_url}`;else{const t=e.target.dataset.code,i=this.react_url.replace("0",this.comment_id),n=new FormData;n.append("reaction",t),n.append("csrfmiddlewaretoken",function get_cookie(e){let t=null;if(document.cookie&&""!==document.cookie){const i=document.cookie.split(";");for(let n=0;nthis.handle_reactions_response(e)))}}async handle_reactions_response(e){const t=await e.json();if(200===e.status||201===e.status){const e=`#cm-reactions-${this.comment_id}`,i=document.querySelector(e);i&&(i.innerHTML=t.html)}else e.status>400&&alert("Something went wrong and your comment reaction could not be processed. Please, reload the page and try again.")}on_react_btn_mouseover(e){this.panel_title_elem&&(this.panel_title_elem.textContent=e.target.dataset.title)}on_react_btn_mouseout(e){this.panel_title_elem.textContent=this.panel_title}set_position(e){this.panel_el.style.display="block";const t=this.get_absolute_coords(this.panel_el),i=this.get_absolute_coords(e),n=t.width,s=t.height,o=t.top,l=t.left,r=i.width,a=i.top,c=i.left,d=c-l+(r/2-n/2),_=a-o-s-8,h=_+10;if(this.panel_el.dataset.fromLeft=d,this.panel_el.dataset.fromTop=h,this.panel_el.dataset.left=d,this.panel_el.dataset.top=_,this.arrow_el){let e=0;e=r/2+c-(d+l);const t=`translate3d(${e}px, 0px, 0)`;this.arrow_el.style.transform=t}}hide(){clearTimeout(this.enter_delay_timeout),this.exit_delat_timeout=setTimeout((()=>{if(this.panel_el){const e=`translate3d(${this.panel_el.dataset.fromLeft}px, ${this.panel_el.dataset.fromTop}px, 0)`;this.panel_el.style.transform=e,this.panel_el.style.opacity=0,this.panel_el.style.display="none",this.panel_el.style.zIndex=0}}),0)}show(e,t){this.comment_id=t,this.next_url=e.dataset.loginNext||"",this.panel_el.style.transform="none",this.set_position(e),this.enter_delay_timeout=setTimeout((()=>{const e=`translate3d(${this.panel_el.dataset.left}px, ${this.panel_el.dataset.top}px, 0)`;this.panel_el.style.zIndex=1,this.panel_el.style.display="block",this.panel_el.style.transform=e,this.panel_el.style.opacity=1}),0)}get_absolute_coords(e){if(!e)return;const t=e.getBoundingClientRect(),i=window.pageXOffset,n=window.pageYOffset;return{width:t.width,height:t.height,top:t.top+n,right:t.right+i,bottom:t.bottom+n,left:t.left+i}}}class ReactionsHandler{constructor(e){if(this.cfg_el=e,this.is_guest="1"===this.cfg_el.getAttribute("data-guest-user"),this.login_url=this.init_login_url(),this.react_url=this.init_react_url(),this.links=document.querySelectorAll("[data-dci=reactions-panel]"),0===this.links.length)throw new Error("Cannot initialize reactions panel => There are no elements with [data-dci=reactions-panel].");this.active_visible_panel=0,this.panels_visibility=new Map,this.event_handlers=[],this.add_event_listeners(),this.listen_to_click_on_links();if(this.panel_el=document.querySelector("[data-dci=reactions-panel-template]"),void 0===this.panel_el)throw new Error("Cannot find element with ${qs_panel}.");const t={panel_el:this.panel_el,is_guest:this.is_guest,login_url:this.login_url,react_url:this.react_url};this.reactions_panel=new ReactionsPanel(t)}init_login_url(){const e=this.cfg_el.getAttribute("data-login-url");if((null===e||0===e.length)&&this.is_guest)throw new Error("Cannot initialize reactions panel => The [data-login-url] attribute does not exist or is empty.");return e}init_react_url(){const e=this.cfg_el.getAttribute("data-react-url");if(null===e||0===e.length){if(!this.is_guest)throw new Error("Cannot initialize reactions panel => The [data-react-url] attribute does not exist or is empty.");console.info("Couldn't find the data-react-url attribute, but the user is anonymous. She has to login first in order to post comment reactions.")}return e}on_document_click(e){const t=e.target.getAttribute("data-dci");t&&"reactions-panel"===t||(this.reactions_panel.hide(),this.active_visible_panel&&(this.panels_visibility.set(this.active_visible_panel,!1),this.active_visible_panel=0))}on_document_key_up(e){"Escape"===e.key&&(this.reactions_panel.hide(),this.active_visible_panel&&(this.panels_visibility.set(this.active_visible_panel,!1),this.active_visible_panel=0))}add_event_listeners(){const e=this.on_document_click.bind(this),t=this.on_document_key_up.bind(this);window.document.addEventListener("click",e),window.document.addEventListener("keyup",t),this.event_handlers.push({elem:window.document,event:"click",handler:this.on_document_click}),this.event_handlers.push({elem:window.document,event:"keyup",handler:this.on_document_key_up})}remove_event_listeners(){for(const e of this.event_handlers)e.elem.removeEventListener(e.event,e.handler)}listen_to_click_on_links(){for(const e of Array.from(this.links)){const t=e.getAttribute("data-comment");if(null===t)continue;const i=this.toggle_reactions_panel(t);e.addEventListener("click",i),this.event_handlers.push({elem:e,event:"click",handler:i}),this.panels_visibility.set(t,!1)}}toggle_reactions_panel(e){return t=>{t.preventDefault();const i=this.panels_visibility.get(e);i?(this.active_visible_panel=0,this.reactions_panel.hide()):(this.active_visible_panel=e,this.reactions_panel.show(t.target,e)),this.panels_visibility.set(e,!i)}}}function init_reactions(){if(null===window.dci)return;const e=document.querySelector("[data-dci=config]");null!==e&&null!==window.dci&&(window.dci.reactions_handler=null,null===window.dci.reactions_handler&&(window.dci.reactions_handler=new ReactionsHandler(e),window.addEventListener("beforeunload",(e=>{window.dci.reactions_handler.remove_event_listeners()}))))}window.dci.init_comments=init_comments,window.dci.init_reactions=init_reactions,window.addEventListener("DOMContentLoaded",(e=>{null!==window.dci&&(init_comments(),init_reactions())}))})(); -//# sourceMappingURL=dci-0.0.1.min.js.map \ No newline at end of file +//# sourceMappingURL=dci-0.0.2.min.js.map \ No newline at end of file diff --git a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.min.js.map b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.min.js.map similarity index 99% rename from django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.min.js.map rename to django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.min.js.map index 683c2a4..6104ced 100644 --- a/django_comments_ink/static/django_comments_ink/dist/dci-0.0.1.min.js.map +++ b/django_comments_ink/static/django_comments_ink/dist/dci-0.0.2.min.js.map @@ -1 +1 @@ -{"version":3,"file":"dci-0.0.1.min.js","mappings":"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","sources":["webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comment_form.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reply_forms.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comments.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_panel.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_handler.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/index.js"],"sourcesContent":["export default class CommentForm {\n constructor(formWrapper) {\n this.formWrapper = formWrapper;\n this.init();\n }\n\n click_on_post(_) { return this.post(\"post\"); }\n\n click_on_preview(_) { return this.post(\"preview\"); }\n\n init() {\n this.formWrapperEl = document.querySelector(this.formWrapper);\n this.formEl = this.formWrapperEl.querySelector(\"form\");\n const post_btn = this.formEl.elements.post;\n const preview_btn = this.formEl.elements.preview;\n post_btn.addEventListener(\"click\", (_) => this.post(\"post\"));\n preview_btn.addEventListener(\"click\", (_) => this.post(\"preview\"));\n // Change the type of the buttons, otherwise the form is submitted.\n post_btn.type = \"button\";\n preview_btn.type = \"button\";\n }\n\n disable_btns(value) {\n this.formEl.elements.post.disabled = value;\n this.formEl.elements.preview.disabled = value;\n }\n\n is_valid() {\n for (const el of this.formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n post(submit_button_name) {\n if (!this.is_valid()) {\n return;\n }\n this.disable_btns(true);\n\n // If the
...
does exist,\n // delete it. If the user clicks again in the \"preview\" button\n // it will be displayed again.\n const preview = this.formWrapperEl.querySelector(\"[data-dci=preview]\");\n if (preview) {\n preview.remove();\n }\n\n const formData = new FormData(this.formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(this.formEl.action, {\n method: 'POST',\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response);\n }\n });\n\n this.disable_btns(false);\n return false; // To prevent calling the action attribute.\n }\n\n async handle_preview_comment_response(response) {\n const data = await response.json();\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n } else if (response.status === 400) {\n this.formEl.innerHTML = data.html;\n }\n }\n\n async handle_post_comment_response(response) {\n const data = await response.json();\n\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.formEl.innerHTML = data.html;\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","export default class ReplyFormsHandler {\n constructor(qsReplyFormBase, qsReplyForms) {\n this.replyFormBase = document.querySelector(qsReplyFormBase);\n this.replyMap = new Map();\n\n const cpage_field = window.dci.page_param || \"cpage\";\n\n for (const elem of document.querySelectorAll(qsReplyForms)) {\n // Extract the reply_to value from the current reply_form.\n // Also, it if does exist, extract the comment's page number too.\n // Then replace the content of elem with a copy of\n // this.replyFormBase and update the fields reply_to\n // and comment's page number.\n const rFormEl = elem.querySelector(\"form\");\n if (rFormEl === null) {\n console.error(\n `Could not find a reply form within one of ` +\n `the elements retrieved with ${qsReplyForms}.`\n );\n return;\n }\n\n const reply_to = rFormEl.elements.reply_to.value;\n const cpage = rFormEl.elements[cpage_field]\n ? rFormEl.elements[cpage_field].value\n : null;\n\n const section = this.replyFormBase.cloneNode(true);\n section.dataset.dci = `reply-form-${reply_to}`;\n\n // Update fields reply_to and cpage..\n const newForm = section.querySelector(\"form\");\n newForm.elements.reply_to.value = reply_to;\n if (cpage) {\n newForm.elements[cpage_field].value = cpage;\n }\n\n const elemParent = elem.parentNode;\n elem.replaceWith(section);\n this.init(reply_to);\n this.replyMap.set(reply_to, elemParent);\n }\n }\n\n init(reply_to, is_active) {\n const qs_section = `[data-dci=reply-form-${reply_to}]`;\n const section = document.querySelector(qs_section);\n\n // Modify the form (update fields, add event listeners).\n const newForm = section.querySelector(\"form\");\n const post_btn = newForm.elements.post;\n post_btn.addEventListener(\"click\", this.send_clicked(reply_to));\n const preview_btn = newForm.elements.preview;\n preview_btn.addEventListener(\"click\", this.preview_clicked(reply_to));\n const cancel_btn = newForm.elements.cancel;\n cancel_btn.addEventListener(\"click\", this.cancel_clicked(reply_to));\n newForm.style.display = \"none\";\n\n // Attach event listener to textarea.\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const ta = divta.querySelector(\"textarea\");\n ta.addEventListener(\"focus\", this.textarea_focus(reply_to));\n\n // If is_active is true, hide the textarea and display the form.\n if (is_active === true) {\n section.classList.add(\"active\");\n divta.style.display = \"none\";\n newForm.style = \"\";\n newForm.elements.comment.focus();\n }\n }\n\n get_map_item(reply_to) {\n const item = this.replyMap.get(reply_to);\n if (item === undefined) {\n const msg = `replyMap doesn't have a key ${reply_to}`;\n console.error(msg);\n throw msg;\n }\n return item;\n }\n\n disable_buttons(formEl, value) {\n formEl.elements.post.disabled = value;\n formEl.elements.preview.disabled = value;\n }\n\n is_valid(formEl) {\n for (const el of formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n textarea_focus(reply_to) {\n // Display the comment form and hide the text area.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n section.classList.toggle(\"active\");\n divta.style.display = \"none\";\n form.style = \"\";\n form.elements.comment.focus();\n };\n }\n\n cancel_clicked(reply_to) {\n // Display the text area and hide the comment form.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const comment_value = form.elements.comment.value;\n divta.querySelector(\"textarea\").value = comment_value;\n section.classList.toggle(\"active\");\n form.style.display = \"none\";\n divta.style = \"\";\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n };\n }\n\n preview_clicked(reply_to) {\n return (_) => {\n this.post(\"preview\", reply_to);\n };\n }\n\n send_clicked(reply_to) {\n return (_) => {\n this.post(\"post\", reply_to);\n };\n }\n\n post(submit_button_name, reply_to) {\n const item = this.get_map_item(reply_to);\n const formEl = item.querySelector(\"form\");\n\n if (!this.is_valid(formEl)) {\n return;\n }\n\n this.disable_buttons(formEl, true);\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n\n const formData = new FormData(formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(formEl.action, {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response, reply_to);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response, reply_to);\n }\n });\n this.disable_buttons(formEl, false);\n return false; // To prevent calling the action attribute.\n }\n\n handle_http_200(item, data, reply_to) {\n item.innerHTML = data.html;\n this.init(reply_to, true); // 2nd param: is_active = true.\n if (data.field_focus) {\n item.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n\n handle_http_201_202_400(item, data) {\n const form = item.querySelector(\"form\");\n form.innerHTML = data.html;\n }\n\n async handle_preview_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n } else if (response.status === 400) {\n this.handle_http_201_202_400(item, data);\n }\n }\n\n async handle_post_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.handle_http_201_202_400(item, data);\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","import CommentForm from \"./comment_form.js\";\nimport ReplyFormsHandler from \"./reply_forms.js\";\n\n\nfunction init_comments() {\n if (window.dci === null) {\n return;\n }\n\n if (window.dci.page_param === undefined) {\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot) {\n window.dci.page_param = rroot.getAttribute(\"data-page-qs-param\");\n }\n }\n\n window.dci.comment_form = null;\n window.dci.reply_forms_handler = null;\n\n /* ----------------------------------------------\n * Initialize main comment form.\n */\n const qs_cform = \"[data-dci=comment-form]\";\n if (window.dci.comment_form === null &&\n document.querySelector(qs_cform)\n ) {\n window.dci.comment_form = new CommentForm(qs_cform);\n }\n\n /* ----------------------------------------------\n * Initialize reply forms.\n */\n const qs_rform_base = \"[data-dci=reply-form-template]\";\n const qs_rforms = \"[data-dci=reply-form]\";\n if (window.dci.reply_forms_handler === null &&\n document.querySelector(qs_rform_base) &&\n document.querySelectorAll(qs_rforms)\n ) {\n window.dci.reply_forms_handler = new ReplyFormsHandler(qs_rform_base, qs_rforms);\n }\n}\n\nexport { init_comments };\n","const enter_delay = 0;\nconst exit_delay = 0;\n\nfunction get_cookie(name) {\n let cookieValue = null;\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n // Does this cookie string begin with the name we want?\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n}\n\nexport default class ReactionsPanel {\n constructor({panel_el, is_guest, login_url, react_url } = opts) {\n this.panel_el = panel_el;\n // this.panel_el.style.zIndex = 1;\n // this.panel_el.style.display = \"block\";\n this.arrow_el = panel_el.querySelector(\".arrow\");\n this.is_guest = is_guest;\n this.login_url = login_url;\n this.react_url = react_url;\n\n // -----------------------------------------------------\n // The panel_title_elem and its content panel_title will\n // change when the user hover the buttons of the panel.\n\n this.panel_title = \"\";\n this.panel_title_elem = this.panel_el.querySelector(\".title\");\n if (this.panel_title_elem) {\n this.panel_title = this.panel_title_elem.textContent;\n }\n\n // -----------------------------------------\n // The comment_id is necessary to know which\n // comment will receive the reaction code.\n\n this.comment_id = 0; // Valid comment_id must be > 0.\n this.next_url = \"\"; // Comment URL to come back after log in.\n\n this.on_react_btn_click = this.on_react_btn_click.bind(this);\n this.on_react_btn_mouseover = this.on_react_btn_mouseover.bind(this);\n this.on_react_btn_mouseout = this.on_react_btn_mouseout.bind(this);\n this.add_event_listeners();\n }\n\n add_event_listeners() {\n const buttons = this.panel_el.querySelectorAll(\"BUTTON\");\n for (const btn of Array.from(buttons)) {\n btn.addEventListener(\"click\", this.on_react_btn_click);\n btn.addEventListener(\"mouseover\", this.on_react_btn_mouseover);\n btn.addEventListener(\"mouseout\", this.on_react_btn_mouseout);\n }\n }\n\n on_react_btn_click(event) {\n if (!this.is_guest) {\n const code = event.target.dataset.code;\n const react_url = this.react_url.replace(\"0\", this.comment_id);\n const formData = new FormData();\n formData.append(\"reaction\", code);\n formData.append(\"csrfmiddlewaretoken\", get_cookie(\"csrftoken\"));\n\n fetch(react_url, {\n method: \"POST\",\n cache: \"no-cache\",\n credentials: \"same-origin\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => this.handle_reactions_response(response));\n } else {\n window.location.href = `${this.login_url}?next=${this.next_url}`;\n }\n }\n\n async handle_reactions_response(response) {\n const data = await response.json();\n if (response.status === 200 || response.status === 201) {\n const cm_reactions_qs = `#cm-reactions-${this.comment_id}`;\n const cm_reactions_el = document.querySelector(cm_reactions_qs);\n if (cm_reactions_el) {\n cm_reactions_el.innerHTML = data.html;\n }\n } else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment reaction could not \" +\n \"be processed. Please, reload the page and try again.\"\n );\n }\n }\n\n on_react_btn_mouseover(event) {\n if (this.panel_title_elem) {\n this.panel_title_elem.textContent = event.target.dataset.title;\n }\n }\n\n on_react_btn_mouseout(_) {\n this.panel_title_elem.textContent = this.panel_title;\n }\n\n set_position(trigger_elem) {\n this.panel_el.style.display = \"block\";\n\n const panel_elem_coords = this.get_absolute_coords(this.panel_el);\n const trigger_elem_coords = this.get_absolute_coords(trigger_elem);\n\n const panel_elem_width = panel_elem_coords.width;\n const panel_elem_height = panel_elem_coords.height;\n const panel_elem_top = panel_elem_coords.top;\n const panel_elem_left = panel_elem_coords.left;\n\n const trigger_elem_width = trigger_elem_coords.width;\n const trigger_elem_top = trigger_elem_coords.top;\n const trigger_elem_left = trigger_elem_coords.left;\n\n const top_diff = trigger_elem_top - panel_elem_top;\n const left_diff = trigger_elem_left - panel_elem_left;\n\n // This group of const values can be hardcoded somewhere else.\n // const position = \"auto\";\n const margin = 8;\n\n const width_center = trigger_elem_width / 2 - panel_elem_width / 2;\n\n const left = left_diff + width_center;\n const top = top_diff - panel_elem_height - margin;\n const from_top = top + 10;\n\n this.panel_el.dataset.fromLeft = left;\n this.panel_el.dataset.fromTop = from_top;\n this.panel_el.dataset.left = left;\n this.panel_el.dataset.top = top;\n\n // Arrow.\n if (this.arrow_el) {\n let arrow_left = 0;\n const full_left = left + panel_elem_left;\n const t_width_center = trigger_elem_width / 2 + trigger_elem_left;\n arrow_left = t_width_center - full_left;\n const transform_text = `translate3d(${arrow_left}px, 0px, 0)`;\n this.arrow_el.style.transform = transform_text;\n }\n }\n\n hide() {\n clearTimeout(this.enter_delay_timeout);\n\n this.exit_delat_timeout = setTimeout(() => {\n if (this.panel_el) {\n const left = this.panel_el.dataset.fromLeft;\n const top = this.panel_el.dataset.fromTop;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 0;\n this.panel_el.style.display = \"none\";\n this.panel_el.style.zIndex = 0;\n }\n }, exit_delay);\n }\n\n show(trigger_elem, comment_id) {\n this.comment_id = comment_id;\n this.next_url = trigger_elem.dataset.loginNext || \"\";\n this.panel_el.style.transform = \"none\";\n this.set_position(trigger_elem);\n\n this.enter_delay_timeout = setTimeout(() => {\n const left = this.panel_el.dataset.left;\n const top = this.panel_el.dataset.top;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.zIndex = 1;\n this.panel_el.style.display = \"block\";\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 1;\n }, enter_delay);\n }\n\n get_absolute_coords(elem) {\n if (!elem) {\n return;\n }\n\n const box = elem.getBoundingClientRect();\n const page_x = window.pageXOffset;\n const page_y = window.pageYOffset;\n\n return {\n width: box.width,\n height: box.height,\n top: box.top + page_y,\n right: box.right + page_x,\n bottom: box.bottom + page_y,\n left: box.left + page_x,\n };\n }\n}\n","import ReactionsPanel from \"./reactions_panel\";\n\nexport default class ReactionsHandler {\n constructor(configEl) {\n this.cfg_el = configEl;\n this.is_guest = this.cfg_el.getAttribute(\"data-guest-user\") === \"1\";\n this.login_url = this.init_login_url();\n this.react_url = this.init_react_url();\n\n // Initialize the buttons panels and their components.\n this.links = document.querySelectorAll(\"[data-dci=reactions-panel]\");\n if (this.links.length === 0) {\n throw new Error(\n \"Cannot initialize reactions panel => There are \" +\n \"no elements with [data-dci=reactions-panel].\");\n }\n this.active_visible_panel = 0;\n this.panels_visibility = new Map(); // Keys are 'comment_id'.\n this.event_handlers = [];\n this.add_event_listeners();\n this.listen_to_click_on_links();\n const qs_panel = \"[data-dci=reactions-panel-template]\";\n this.panel_el = document.querySelector(qs_panel);\n if (this.panel_el === undefined) {\n throw new Error(\"Cannot find element with ${qs_panel}.\");\n }\n\n // Create object of class ReactionsPanel in charge of showing and\n // hiding the reactions panel around the clicked 'react' link.\n const opts = {\n panel_el: this.panel_el,\n is_guest: this.is_guest,\n login_url: this.login_url,\n react_url: this.react_url\n };\n this.reactions_panel = new ReactionsPanel(opts);\n }\n\n init_login_url() {\n const url = this.cfg_el.getAttribute(\"data-login-url\");\n if (url === null || url.length === 0) {\n if (this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-login-url] attribute does not exist or is empty.\");\n }\n }\n return url;\n }\n\n init_react_url() {\n const url = this.cfg_el.getAttribute(\"data-react-url\");\n if (url === null || url.length === 0) {\n if (!this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-react-url] attribute does not exist or is empty.\");\n } else {\n console.info(\"Couldn't find the data-react-url attribute, \" +\n \"but the user is anonymous. She has to login first in \" +\n \"order to post comment reactions.\");\n }\n }\n return url;\n }\n\n on_document_click(event) {\n const data_attr = event.target.getAttribute(\"data-dci\");\n if (!data_attr || data_attr !== \"reactions-panel\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n on_document_key_up(event) {\n if (event.key === \"Escape\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n add_event_listeners() {\n const onDocumentClickHandler = this.on_document_click.bind(this);\n const onDocumentKeyUpHandler = this.on_document_key_up.bind(this);\n\n window.document.addEventListener('click', onDocumentClickHandler);\n window.document.addEventListener('keyup', onDocumentKeyUpHandler);\n\n this.event_handlers.push({\n elem: window.document,\n event: 'click',\n handler: this.on_document_click,\n });\n this.event_handlers.push({\n elem: window.document,\n event: 'keyup',\n handler: this.on_document_key_up,\n });\n }\n\n remove_event_listeners() {\n for (const item of this.event_handlers) {\n item.elem.removeEventListener(item.event, item.handler);\n }\n }\n\n listen_to_click_on_links() {\n for (const elem of Array.from(this.links)) {\n const comment_id = elem.getAttribute(\"data-comment\");\n if (comment_id === null) {\n continue;\n }\n const click_handler = this.toggle_reactions_panel(comment_id);\n elem.addEventListener(\"click\", click_handler);\n this.event_handlers.push({\n 'elem': elem,\n 'event': 'click',\n 'handler': click_handler\n });\n this.panels_visibility.set(comment_id, false); // Not visible yet.\n }\n }\n\n toggle_reactions_panel(comment_id) {\n return (event) => {\n event.preventDefault();\n const is_visible = this.panels_visibility.get(comment_id);\n if (!is_visible) {\n this.active_visible_panel = comment_id;\n this.reactions_panel.show(event.target, comment_id);\n } else {\n this.active_visible_panel = 0;\n this.reactions_panel.hide();\n }\n this.panels_visibility.set(comment_id, !is_visible);\n };\n }\n}\n","import ReactionsHandler from \"./reactions_handler\";\n\nfunction init_reactions() {\n if (window.dci === null) {\n return;\n }\n\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot === null || window.dci === null) {\n return;\n }\n\n window.dci.reactions_handler = null;\n\n /* ----------------------------------------------\n * Initialize reactions_handler, in charge\n * of all reactions popover components.\n */\n if (window.dci.reactions_handler === null) {\n window.dci.reactions_handler = new ReactionsHandler(rroot);\n window.addEventListener(\"beforeunload\", (_) => {\n window.dci.reactions_handler.remove_event_listeners();\n });\n\n }\n}\n\nexport { init_reactions };\n","import { init_comments } from \"./comments.js\";\nimport { init_reactions } from \"./reactions.js\";\n\nwindow.dci.init_comments = init_comments;\nwindow.dci.init_reactions = init_reactions;\n\nwindow.addEventListener(\"DOMContentLoaded\", (_) => {\n if (window.dci === null) {\n return;\n }\n\n init_comments();\n init_reactions();\n});\n"],"names":["CommentForm","constructor","formWrapper","this","init","click_on_post","_","post","click_on_preview","formWrapperEl","document","querySelector","formEl","post_btn","elements","preview_btn","preview","addEventListener","type","disable_btns","value","disabled","is_valid","el","querySelectorAll","reportValidity","focus","submit_button_name","remove","formData","FormData","undefined","append","fetch","action","method","headers","body","then","response","handle_preview_comment_response","handle_post_comment_response","async","data","json","status","innerHTML","html","field_focus","alert","ReplyFormsHandler","qsReplyFormBase","qsReplyForms","replyFormBase","replyMap","Map","cpage_field","window","dci","page_param","elem","rFormEl","console","error","reply_to","cpage","section","cloneNode","dataset","newForm","elemParent","parentNode","replaceWith","set","is_active","qs_section","send_clicked","preview_clicked","cancel","cancel_clicked","style","display","divta","textarea_focus","classList","add","comment","get_map_item","item","get","msg","disable_buttons","form","toggle","comment_value","previewEl","handle_http_200","handle_http_201_202_400","init_comments","rroot","getAttribute","comment_form","reply_forms_handler","qs_cform","qs_rform_base","qs_rforms","ReactionsPanel","panel_el","is_guest","login_url","react_url","opts","arrow_el","panel_title","panel_title_elem","textContent","comment_id","next_url","on_react_btn_click","bind","on_react_btn_mouseover","on_react_btn_mouseout","add_event_listeners","buttons","btn","Array","from","event","location","href","code","target","replace","get_cookie","name","cookieValue","cookie","cookies","split","i","length","trim","substring","decodeURIComponent","cache","credentials","handle_reactions_response","cm_reactions_qs","cm_reactions_el","title","set_position","trigger_elem","panel_elem_coords","get_absolute_coords","trigger_elem_coords","panel_elem_width","width","panel_elem_height","height","panel_elem_top","top","panel_elem_left","left","trigger_elem_width","trigger_elem_top","trigger_elem_left","from_top","fromLeft","fromTop","arrow_left","transform_text","transform","hide","clearTimeout","enter_delay_timeout","exit_delat_timeout","setTimeout","opacity","zIndex","show","loginNext","box","getBoundingClientRect","page_x","pageXOffset","page_y","pageYOffset","right","bottom","ReactionsHandler","configEl","cfg_el","init_login_url","init_react_url","links","Error","active_visible_panel","panels_visibility","event_handlers","listen_to_click_on_links","reactions_panel","url","info","on_document_click","data_attr","on_document_key_up","key","onDocumentClickHandler","onDocumentKeyUpHandler","push","handler","remove_event_listeners","removeEventListener","click_handler","toggle_reactions_panel","preventDefault","is_visible","init_reactions","reactions_handler"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"dci-0.0.2.min.js","mappings":"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","sources":["webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comment_form.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reply_forms.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/comments.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_panel.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions_handler.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/reactions.js","webpack://django-comments-ink/./django_comments_ink/static/django_comments_ink/js/index.js"],"sourcesContent":["export default class CommentForm {\n constructor(formWrapper) {\n this.formWrapper = formWrapper;\n this.init();\n }\n\n click_on_post(_) { return this.post(\"post\"); }\n\n click_on_preview(_) { return this.post(\"preview\"); }\n\n init() {\n this.formWrapperEl = document.querySelector(this.formWrapper);\n this.formEl = this.formWrapperEl.querySelector(\"form\");\n const post_btn = this.formEl.elements.post;\n const preview_btn = this.formEl.elements.preview;\n post_btn.addEventListener(\"click\", (_) => this.post(\"post\"));\n preview_btn.addEventListener(\"click\", (_) => this.post(\"preview\"));\n // Change the type of the buttons, otherwise the form is submitted.\n post_btn.type = \"button\";\n preview_btn.type = \"button\";\n }\n\n disable_btns(value) {\n this.formEl.elements.post.disabled = value;\n this.formEl.elements.preview.disabled = value;\n }\n\n is_valid() {\n for (const el of this.formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n post(submit_button_name) {\n if (!this.is_valid()) {\n return;\n }\n this.disable_btns(true);\n\n // If the
...
does exist,\n // delete it. If the user clicks again in the \"preview\" button\n // it will be displayed again.\n const preview = this.formWrapperEl.querySelector(\"[data-dci=preview]\");\n if (preview) {\n preview.remove();\n }\n\n const formData = new FormData(this.formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(this.formEl.action, {\n method: 'POST',\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response);\n }\n });\n\n this.disable_btns(false);\n return false; // To prevent calling the action attribute.\n }\n\n async handle_preview_comment_response(response) {\n const data = await response.json();\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n } else if (response.status === 400) {\n this.formEl.innerHTML = data.html;\n }\n }\n\n async handle_post_comment_response(response) {\n const data = await response.json();\n\n if (response.status === 200) {\n this.formWrapperEl.innerHTML = data.html;\n this.init();\n if (data.field_focus) {\n this.formEl.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.formEl.innerHTML = data.html;\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","export default class ReplyFormsHandler {\n constructor(qsReplyFormBase, qsReplyForms) {\n this.replyFormBase = document.querySelector(qsReplyFormBase);\n this.replyMap = new Map();\n\n const cpage_field = window.dci.page_param || \"cpage\";\n\n for (const elem of document.querySelectorAll(qsReplyForms)) {\n // Extract the reply_to value from the current reply_form.\n // Also, it if does exist, extract the comment's page number too.\n // Then replace the content of elem with a copy of\n // this.replyFormBase and update the fields reply_to\n // and comment's page number.\n const rFormEl = elem.querySelector(\"form\");\n if (rFormEl === null) {\n console.error(\n `Could not find a reply form within one of ` +\n `the elements retrieved with ${qsReplyForms}.`\n );\n return;\n }\n\n const reply_to = rFormEl.elements.reply_to.value;\n const cpage = rFormEl.elements[cpage_field]\n ? rFormEl.elements[cpage_field].value\n : null;\n\n const section = this.replyFormBase.cloneNode(true);\n section.dataset.dci = `reply-form-${reply_to}`;\n\n // Update fields reply_to and cpage..\n const newForm = section.querySelector(\"form\");\n newForm.elements.reply_to.value = reply_to;\n if (cpage) {\n newForm.elements[cpage_field].value = cpage;\n }\n\n const elemParent = elem.parentNode;\n elem.replaceWith(section);\n this.init(reply_to);\n this.replyMap.set(reply_to, elemParent);\n }\n }\n\n init(reply_to, is_active) {\n const qs_section = `[data-dci=reply-form-${reply_to}]`;\n const section = document.querySelector(qs_section);\n\n // Modify the form (update fields, add event listeners).\n const newForm = section.querySelector(\"form\");\n const post_btn = newForm.elements.post;\n post_btn.addEventListener(\"click\", this.send_clicked(reply_to));\n const preview_btn = newForm.elements.preview;\n preview_btn.addEventListener(\"click\", this.preview_clicked(reply_to));\n const cancel_btn = newForm.elements.cancel;\n cancel_btn.addEventListener(\"click\", this.cancel_clicked(reply_to));\n newForm.style.display = \"none\";\n\n // Attach event listener to textarea.\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const ta = divta.querySelector(\"textarea\");\n ta.addEventListener(\"focus\", this.textarea_focus(reply_to));\n\n // If is_active is true, hide the textarea and display the form.\n if (is_active === true) {\n section.classList.add(\"active\");\n divta.style.display = \"none\";\n newForm.style = \"\";\n newForm.elements.comment.focus();\n }\n }\n\n get_map_item(reply_to) {\n const item = this.replyMap.get(reply_to);\n if (item === undefined) {\n const msg = `replyMap doesn't have a key ${reply_to}`;\n console.error(msg);\n throw msg;\n }\n return item;\n }\n\n disable_buttons(formEl, value) {\n formEl.elements.post.disabled = value;\n formEl.elements.preview.disabled = value;\n }\n\n is_valid(formEl) {\n for (const el of formEl.querySelectorAll(\"[required]\")) {\n if (!el.reportValidity()) {\n el.focus();\n return false;\n }\n }\n return true;\n }\n\n textarea_focus(reply_to) {\n // Display the comment form and hide the text area.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n section.classList.toggle(\"active\");\n divta.style.display = \"none\";\n form.style = \"\";\n form.elements.comment.focus();\n };\n }\n\n cancel_clicked(reply_to) {\n // Display the text area and hide the comment form.\n return (_) => {\n const item = this.get_map_item(reply_to);\n const qs_section = `[data-dci=reply-form-${reply_to}`;\n const section = item.querySelector(qs_section);\n const form = section.querySelector(\"form\");\n const divta = section.querySelector(\"[data-dci=reply-textarea]\");\n const comment_value = form.elements.comment.value;\n divta.querySelector(\"textarea\").value = comment_value;\n section.classList.toggle(\"active\");\n form.style.display = \"none\";\n divta.style = \"\";\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n };\n }\n\n preview_clicked(reply_to) {\n return (_) => {\n this.post(\"preview\", reply_to);\n };\n }\n\n send_clicked(reply_to) {\n return (_) => {\n this.post(\"post\", reply_to);\n };\n }\n\n post(submit_button_name, reply_to) {\n const item = this.get_map_item(reply_to);\n const formEl = item.querySelector(\"form\");\n\n if (!this.is_valid(formEl)) {\n return;\n }\n\n this.disable_buttons(formEl, true);\n\n const previewEl = item.querySelector(\"[data-dci=preview]\");\n if (previewEl) {\n previewEl.remove();\n }\n\n const formData = new FormData(formEl);\n if (submit_button_name !== undefined) {\n formData.append(submit_button_name, 1);\n }\n\n fetch(formEl.action, {\n method: \"POST\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => {\n if (submit_button_name === \"preview\") {\n this.handle_preview_comment_response(response, reply_to);\n } else if (submit_button_name === \"post\") {\n this.handle_post_comment_response(response, reply_to);\n }\n });\n this.disable_buttons(formEl, false);\n return false; // To prevent calling the action attribute.\n }\n\n handle_http_200(item, data, reply_to) {\n item.innerHTML = data.html;\n this.init(reply_to, true); // 2nd param: is_active = true.\n if (data.field_focus) {\n item.querySelector(`[name=${data.field_focus}]`).focus();\n }\n }\n\n handle_http_201_202_400(item, data) {\n const form = item.querySelector(\"form\");\n form.innerHTML = data.html;\n }\n\n async handle_preview_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n } else if (response.status === 400) {\n this.handle_http_201_202_400(item, data);\n }\n }\n\n async handle_post_comment_response(response, reply_to) {\n const item = this.get_map_item(reply_to);\n const data = await response.json();\n\n if (response.status === 200) {\n this.handle_http_200(item, data, reply_to);\n }\n else if (\n response.status === 201 ||\n response.status === 202 ||\n response.status === 400\n ) {\n this.handle_http_201_202_400(item, data);\n }\n else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment could not be \" +\n \"processed. Please, reload the page and try again.\"\n );\n }\n }\n}\n","import CommentForm from \"./comment_form.js\";\nimport ReplyFormsHandler from \"./reply_forms.js\";\n\n\nfunction init_comments() {\n if (window.dci === null) {\n return;\n }\n\n if (window.dci.page_param === undefined) {\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot) {\n window.dci.page_param = rroot.getAttribute(\"data-page-qs-param\");\n }\n }\n\n window.dci.comment_form = null;\n window.dci.reply_forms_handler = null;\n\n /* ----------------------------------------------\n * Initialize main comment form.\n */\n const qs_cform = \"[data-dci=comment-form]\";\n if (window.dci.comment_form === null &&\n document.querySelector(qs_cform)\n ) {\n window.dci.comment_form = new CommentForm(qs_cform);\n }\n\n /* ----------------------------------------------\n * Initialize reply forms.\n */\n const qs_rform_base = \"[data-dci=reply-form-template]\";\n const qs_rforms = \"[data-dci=reply-form]\";\n if (window.dci.reply_forms_handler === null &&\n document.querySelector(qs_rform_base) &&\n document.querySelectorAll(qs_rforms)\n ) {\n window.dci.reply_forms_handler = new ReplyFormsHandler(qs_rform_base, qs_rforms);\n }\n}\n\nexport { init_comments };\n","const enter_delay = 0;\nconst exit_delay = 0;\n\nfunction get_cookie(name) {\n let cookieValue = null;\n if (document.cookie && document.cookie !== '') {\n const cookies = document.cookie.split(';');\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i].trim();\n // Does this cookie string begin with the name we want?\n if (cookie.substring(0, name.length + 1) === (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n}\n\nexport default class ReactionsPanel {\n constructor({panel_el, is_guest, login_url, react_url } = opts) {\n this.panel_el = panel_el;\n // this.panel_el.style.zIndex = 1;\n // this.panel_el.style.display = \"block\";\n this.arrow_el = panel_el.querySelector(\".arrow\");\n this.is_guest = is_guest;\n this.login_url = login_url;\n this.react_url = react_url;\n\n // -----------------------------------------------------\n // The panel_title_elem and its content panel_title will\n // change when the user hover the buttons of the panel.\n\n this.panel_title = \"\";\n this.panel_title_elem = this.panel_el.querySelector(\".title\");\n if (this.panel_title_elem) {\n this.panel_title = this.panel_title_elem.textContent;\n }\n\n // -----------------------------------------\n // The comment_id is necessary to know which\n // comment will receive the reaction code.\n\n this.comment_id = 0; // Valid comment_id must be > 0.\n this.next_url = \"\"; // Comment URL to come back after log in.\n\n this.on_react_btn_click = this.on_react_btn_click.bind(this);\n this.on_react_btn_mouseover = this.on_react_btn_mouseover.bind(this);\n this.on_react_btn_mouseout = this.on_react_btn_mouseout.bind(this);\n this.add_event_listeners();\n }\n\n add_event_listeners() {\n const buttons = this.panel_el.querySelectorAll(\"BUTTON\");\n for (const btn of Array.from(buttons)) {\n btn.addEventListener(\"click\", this.on_react_btn_click);\n btn.addEventListener(\"mouseover\", this.on_react_btn_mouseover);\n btn.addEventListener(\"mouseout\", this.on_react_btn_mouseout);\n }\n }\n\n on_react_btn_click(event) {\n if (!this.is_guest) {\n const code = event.target.dataset.code;\n const react_url = this.react_url.replace(\"0\", this.comment_id);\n const formData = new FormData();\n formData.append(\"reaction\", code);\n formData.append(\"csrfmiddlewaretoken\", get_cookie(\"csrftoken\"));\n\n fetch(react_url, {\n method: \"POST\",\n cache: \"no-cache\",\n credentials: \"same-origin\",\n headers: {\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: formData\n }).then(response => this.handle_reactions_response(response));\n } else {\n window.location.href = `${this.login_url}?next=${this.next_url}`;\n }\n }\n\n async handle_reactions_response(response) {\n const data = await response.json();\n if (response.status === 200 || response.status === 201) {\n const cm_reactions_qs = `#cm-reactions-${this.comment_id}`;\n const cm_reactions_el = document.querySelector(cm_reactions_qs);\n if (cm_reactions_el) {\n cm_reactions_el.innerHTML = data.html;\n }\n } else if (response.status > 400) {\n alert(\n \"Something went wrong and your comment reaction could not \" +\n \"be processed. Please, reload the page and try again.\"\n );\n }\n }\n\n on_react_btn_mouseover(event) {\n if (this.panel_title_elem) {\n this.panel_title_elem.textContent = event.target.dataset.title;\n }\n }\n\n on_react_btn_mouseout(_) {\n this.panel_title_elem.textContent = this.panel_title;\n }\n\n set_position(trigger_elem) {\n this.panel_el.style.display = \"block\";\n\n const panel_elem_coords = this.get_absolute_coords(this.panel_el);\n const trigger_elem_coords = this.get_absolute_coords(trigger_elem);\n\n const panel_elem_width = panel_elem_coords.width;\n const panel_elem_height = panel_elem_coords.height;\n const panel_elem_top = panel_elem_coords.top;\n const panel_elem_left = panel_elem_coords.left;\n\n const trigger_elem_width = trigger_elem_coords.width;\n const trigger_elem_top = trigger_elem_coords.top;\n const trigger_elem_left = trigger_elem_coords.left;\n\n const top_diff = trigger_elem_top - panel_elem_top;\n const left_diff = trigger_elem_left - panel_elem_left;\n\n // This group of const values can be hardcoded somewhere else.\n // const position = \"auto\";\n const margin = 8;\n\n const width_center = trigger_elem_width / 2 - panel_elem_width / 2;\n\n const left = left_diff + width_center;\n const top = top_diff - panel_elem_height - margin;\n const from_top = top + 10;\n\n this.panel_el.dataset.fromLeft = left;\n this.panel_el.dataset.fromTop = from_top;\n this.panel_el.dataset.left = left;\n this.panel_el.dataset.top = top;\n\n // Arrow.\n if (this.arrow_el) {\n let arrow_left = 0;\n const full_left = left + panel_elem_left;\n const t_width_center = trigger_elem_width / 2 + trigger_elem_left;\n arrow_left = t_width_center - full_left;\n const transform_text = `translate3d(${arrow_left}px, 0px, 0)`;\n this.arrow_el.style.transform = transform_text;\n }\n }\n\n hide() {\n clearTimeout(this.enter_delay_timeout);\n\n this.exit_delat_timeout = setTimeout(() => {\n if (this.panel_el) {\n const left = this.panel_el.dataset.fromLeft;\n const top = this.panel_el.dataset.fromTop;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 0;\n this.panel_el.style.display = \"none\";\n this.panel_el.style.zIndex = 0;\n }\n }, exit_delay);\n }\n\n show(trigger_elem, comment_id) {\n this.comment_id = comment_id;\n this.next_url = trigger_elem.dataset.loginNext || \"\";\n this.panel_el.style.transform = \"none\";\n this.set_position(trigger_elem);\n\n this.enter_delay_timeout = setTimeout(() => {\n const left = this.panel_el.dataset.left;\n const top = this.panel_el.dataset.top;\n const transform_text = `translate3d(${left}px, ${top}px, 0)`;\n\n this.panel_el.style.zIndex = 1;\n this.panel_el.style.display = \"block\";\n this.panel_el.style.transform = transform_text;\n this.panel_el.style.opacity = 1;\n }, enter_delay);\n }\n\n get_absolute_coords(elem) {\n if (!elem) {\n return;\n }\n\n const box = elem.getBoundingClientRect();\n const page_x = window.pageXOffset;\n const page_y = window.pageYOffset;\n\n return {\n width: box.width,\n height: box.height,\n top: box.top + page_y,\n right: box.right + page_x,\n bottom: box.bottom + page_y,\n left: box.left + page_x,\n };\n }\n}\n","import ReactionsPanel from \"./reactions_panel\";\n\nexport default class ReactionsHandler {\n constructor(configEl) {\n this.cfg_el = configEl;\n this.is_guest = this.cfg_el.getAttribute(\"data-guest-user\") === \"1\";\n this.login_url = this.init_login_url();\n this.react_url = this.init_react_url();\n\n // Initialize the buttons panels and their components.\n this.links = document.querySelectorAll(\"[data-dci=reactions-panel]\");\n if (this.links.length === 0) {\n throw new Error(\n \"Cannot initialize reactions panel => There are \" +\n \"no elements with [data-dci=reactions-panel].\");\n }\n this.active_visible_panel = 0;\n this.panels_visibility = new Map(); // Keys are 'comment_id'.\n this.event_handlers = [];\n this.add_event_listeners();\n this.listen_to_click_on_links();\n const qs_panel = \"[data-dci=reactions-panel-template]\";\n this.panel_el = document.querySelector(qs_panel);\n if (this.panel_el === undefined) {\n throw new Error(\"Cannot find element with ${qs_panel}.\");\n }\n\n // Create object of class ReactionsPanel in charge of showing and\n // hiding the reactions panel around the clicked 'react' link.\n const opts = {\n panel_el: this.panel_el,\n is_guest: this.is_guest,\n login_url: this.login_url,\n react_url: this.react_url\n };\n this.reactions_panel = new ReactionsPanel(opts);\n }\n\n init_login_url() {\n const url = this.cfg_el.getAttribute(\"data-login-url\");\n if (url === null || url.length === 0) {\n if (this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-login-url] attribute does not exist or is empty.\");\n }\n }\n return url;\n }\n\n init_react_url() {\n const url = this.cfg_el.getAttribute(\"data-react-url\");\n if (url === null || url.length === 0) {\n if (!this.is_guest) {\n throw new Error(\"Cannot initialize reactions panel => The \" +\n \"[data-react-url] attribute does not exist or is empty.\");\n } else {\n console.info(\"Couldn't find the data-react-url attribute, \" +\n \"but the user is anonymous. She has to login first in \" +\n \"order to post comment reactions.\");\n }\n }\n return url;\n }\n\n on_document_click(event) {\n const data_attr = event.target.getAttribute(\"data-dci\");\n if (!data_attr || data_attr !== \"reactions-panel\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n on_document_key_up(event) {\n if (event.key === \"Escape\") {\n this.reactions_panel.hide();\n if (this.active_visible_panel) {\n this.panels_visibility.set(this.active_visible_panel, false);\n this.active_visible_panel = 0;\n }\n }\n }\n\n add_event_listeners() {\n const onDocumentClickHandler = this.on_document_click.bind(this);\n const onDocumentKeyUpHandler = this.on_document_key_up.bind(this);\n\n window.document.addEventListener('click', onDocumentClickHandler);\n window.document.addEventListener('keyup', onDocumentKeyUpHandler);\n\n this.event_handlers.push({\n elem: window.document,\n event: 'click',\n handler: this.on_document_click,\n });\n this.event_handlers.push({\n elem: window.document,\n event: 'keyup',\n handler: this.on_document_key_up,\n });\n }\n\n remove_event_listeners() {\n for (const item of this.event_handlers) {\n item.elem.removeEventListener(item.event, item.handler);\n }\n }\n\n listen_to_click_on_links() {\n for (const elem of Array.from(this.links)) {\n const comment_id = elem.getAttribute(\"data-comment\");\n if (comment_id === null) {\n continue;\n }\n const click_handler = this.toggle_reactions_panel(comment_id);\n elem.addEventListener(\"click\", click_handler);\n this.event_handlers.push({\n 'elem': elem,\n 'event': 'click',\n 'handler': click_handler\n });\n this.panels_visibility.set(comment_id, false); // Not visible yet.\n }\n }\n\n toggle_reactions_panel(comment_id) {\n return (event) => {\n event.preventDefault();\n const is_visible = this.panels_visibility.get(comment_id);\n if (!is_visible) {\n this.active_visible_panel = comment_id;\n this.reactions_panel.show(event.target, comment_id);\n } else {\n this.active_visible_panel = 0;\n this.reactions_panel.hide();\n }\n this.panels_visibility.set(comment_id, !is_visible);\n };\n }\n}\n","import ReactionsHandler from \"./reactions_handler\";\n\nfunction init_reactions() {\n if (window.dci === null) {\n return;\n }\n\n const rroot = document.querySelector(\"[data-dci=config]\");\n if (rroot === null || window.dci === null) {\n return;\n }\n\n window.dci.reactions_handler = null;\n\n /* ----------------------------------------------\n * Initialize reactions_handler, in charge\n * of all reactions popover components.\n */\n if (window.dci.reactions_handler === null) {\n window.dci.reactions_handler = new ReactionsHandler(rroot);\n window.addEventListener(\"beforeunload\", (_) => {\n window.dci.reactions_handler.remove_event_listeners();\n });\n\n }\n}\n\nexport { init_reactions };\n","import { init_comments } from \"./comments.js\";\nimport { init_reactions } from \"./reactions.js\";\n\nwindow.dci.init_comments = init_comments;\nwindow.dci.init_reactions = init_reactions;\n\nwindow.addEventListener(\"DOMContentLoaded\", (_) => {\n if (window.dci === null) {\n return;\n }\n\n init_comments();\n init_reactions();\n});\n"],"names":["CommentForm","constructor","formWrapper","this","init","click_on_post","_","post","click_on_preview","formWrapperEl","document","querySelector","formEl","post_btn","elements","preview_btn","preview","addEventListener","type","disable_btns","value","disabled","is_valid","el","querySelectorAll","reportValidity","focus","submit_button_name","remove","formData","FormData","undefined","append","fetch","action","method","headers","body","then","response","handle_preview_comment_response","handle_post_comment_response","async","data","json","status","innerHTML","html","field_focus","alert","ReplyFormsHandler","qsReplyFormBase","qsReplyForms","replyFormBase","replyMap","Map","cpage_field","window","dci","page_param","elem","rFormEl","console","error","reply_to","cpage","section","cloneNode","dataset","newForm","elemParent","parentNode","replaceWith","set","is_active","qs_section","send_clicked","preview_clicked","cancel","cancel_clicked","style","display","divta","textarea_focus","classList","add","comment","get_map_item","item","get","msg","disable_buttons","form","toggle","comment_value","previewEl","handle_http_200","handle_http_201_202_400","init_comments","rroot","getAttribute","comment_form","reply_forms_handler","qs_cform","qs_rform_base","qs_rforms","ReactionsPanel","panel_el","is_guest","login_url","react_url","opts","arrow_el","panel_title","panel_title_elem","textContent","comment_id","next_url","on_react_btn_click","bind","on_react_btn_mouseover","on_react_btn_mouseout","add_event_listeners","buttons","btn","Array","from","event","location","href","code","target","replace","get_cookie","name","cookieValue","cookie","cookies","split","i","length","trim","substring","decodeURIComponent","cache","credentials","handle_reactions_response","cm_reactions_qs","cm_reactions_el","title","set_position","trigger_elem","panel_elem_coords","get_absolute_coords","trigger_elem_coords","panel_elem_width","width","panel_elem_height","height","panel_elem_top","top","panel_elem_left","left","trigger_elem_width","trigger_elem_top","trigger_elem_left","from_top","fromLeft","fromTop","arrow_left","transform_text","transform","hide","clearTimeout","enter_delay_timeout","exit_delat_timeout","setTimeout","opacity","zIndex","show","loginNext","box","getBoundingClientRect","page_x","pageXOffset","page_y","pageYOffset","right","bottom","ReactionsHandler","configEl","cfg_el","init_login_url","init_react_url","links","Error","active_visible_panel","panels_visibility","event_handlers","listen_to_click_on_links","reactions_panel","url","info","on_document_click","data_attr","on_document_key_up","key","onDocumentClickHandler","onDocumentKeyUpHandler","push","handler","remove_event_listeners","removeEventListener","click_handler","toggle_reactions_panel","preventDefault","is_visible","init_reactions","reactions_handler"],"sourceRoot":""} \ No newline at end of file diff --git a/django_comments_ink/views.py b/django_comments_ink/views.py index b335227..87f0f38 100644 --- a/django_comments_ink/views.py +++ b/django_comments_ink/views.py @@ -46,6 +46,7 @@ TmpInkComment, ) + InkComment = get_comment_model() @@ -1083,7 +1084,11 @@ def react(request, comment_id, next=None): ) for pth in _reacted_js_tmpl ] - context = {"comment": comment} + max_users_in_tooltip = settings.COMMENTS_INK_MAX_USERS_IN_TOOLTIP + context = { + "comment": comment, + "max_users_in_tooltip": max_users_in_tooltip, + } status = 201 if created else 200 return json_res(request, template_list, context, status=status) diff --git a/js_tests/tests/scene1/index.html b/js_tests/tests/scene1/index.html index 69ee69f..889f906 100644 --- a/js_tests/tests/scene1/index.html +++ b/js_tests/tests/scene1/index.html @@ -97,7 +97,7 @@
Post your comment
- +
diff --git a/js_tests/tests/scene2/index.html b/js_tests/tests/scene2/index.html index c1ba6bf..26e6d47 100644 --- a/js_tests/tests/scene2/index.html +++ b/js_tests/tests/scene2/index.html @@ -147,7 +147,7 @@
Post your comment
- +
diff --git a/js_tests/tests/scene3/index.html b/js_tests/tests/scene3/index.html index 8a820f9..aa7315a 100644 --- a/js_tests/tests/scene3/index.html +++ b/js_tests/tests/scene3/index.html @@ -149,7 +149,7 @@
Post your comment
- +
diff --git a/package.json b/package.json index 190e121..d9e6b78 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "django-comments-ink", "private": true, - "version": "0.0.1", + "version": "0.0.2", "description": "Test the frontend modules of django-comments-ink", "scripts": { "pretest": "eslint django_comments_ink/static/django_comments_ink", diff --git a/pyproject.toml b/pyproject.toml index fea57b7..3059d1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,20 +14,6 @@ exclude_lines = [ line-length = 80 extend-exclude = '''pqenv|psenv''' -[tool.isort] -profile = "black" -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -ensure_newline_before_comments = true -line_length = 80 -src_paths = ["django_comments_xtd", "demos"] -extend_skip_glob = [ - "**/pqenv/**", - "**/psenv/**", -] - [tool.pytest] addopts = "--create-db" django_find_project = false diff --git a/setup.py b/setup.py index 4573db3..ad166b7 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( name="django-comments-ink", - version="0.0.1", + version="0.0.2", packages=find_packages(), include_package_data=True, license="MIT",