680 lines
19 KiB
JavaScript
680 lines
19 KiB
JavaScript
// steps:
|
|
// اضافه کردن ویژگی های زیر به تگ های والد.
|
|
// 1- :ref="'section-' + propertyName"
|
|
// 2- :id="'section-' + propertyName"
|
|
// 3- @mouseup="onMouseUp"
|
|
// اضافه کردن کامپوننت های JahatCommentsForm و JahatCommentsList به صفحه
|
|
|
|
import tahrirApis from "~/apis/tahrirApi";
|
|
// import tinyTahrir from "assets/tahrir/vendors/tinymce-files/tinytahrir";
|
|
import HttpService from "~/services/httpService";
|
|
import repoApi from "~/apis/repoApi";
|
|
export default {
|
|
created() {
|
|
window.addEventListener("scroll", this.handleScroll);
|
|
},
|
|
beforeMount() {
|
|
this.commentHttpService = new HttpService(
|
|
import.meta.env.VITE_TAHRIR_BASE_URL
|
|
);
|
|
this.httpService1 = new HttpService(import.meta.env.VITE_MESSAGE_BASE_URL);
|
|
this.id = this.$route.params.id;
|
|
},
|
|
destroyed() {
|
|
window.removeEventListener("scroll", this.handleScroll);
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
id: "",
|
|
comments: [],
|
|
newComment: false,
|
|
selectedText: null,
|
|
globalGuid: undefined,
|
|
paragraphId: undefined,
|
|
paragraphParentId: undefined,
|
|
commentHttpService: undefined,
|
|
httpService1: undefined,
|
|
};
|
|
},
|
|
methods: {
|
|
/*
|
|
open comment form when user select a text
|
|
*/
|
|
onMouseUp($event) {
|
|
// console.log($event.target.id)
|
|
// Get selected text and encode it
|
|
const selection = encodeURIComponent(
|
|
this.getSelected().toString()
|
|
).replace(/[!'()*]/g);
|
|
if (selection) {
|
|
this.selectedText = selection;
|
|
|
|
this.setParagraphId($event);
|
|
this.createPopup($event, "linkPopup");
|
|
}
|
|
},
|
|
/*
|
|
extract user selected text
|
|
*/
|
|
getSelected() {
|
|
if (window.getSelection) {
|
|
return window.getSelection();
|
|
} else if (document.getSelection) {
|
|
return document.getSelection();
|
|
} else {
|
|
var selection = document.selection && document.selection.createRange();
|
|
if (selection.text) {
|
|
return selection.text;
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
setParagraphId(ev) {
|
|
this.paragraphId = ev.target.id;
|
|
this.paragraphParentId = ev.target.parentNode?.id;
|
|
},
|
|
/*
|
|
create comment popup and place it on top fo the selected text;
|
|
*/
|
|
createPopup(event) {
|
|
this.openCommentForm();
|
|
|
|
// Get cursor position
|
|
// const posX = event.clientX - 130;
|
|
// const posY = event.clientY - 200;
|
|
const posX = event.clientX;
|
|
const posY = event.clientY;
|
|
|
|
try {
|
|
this.$refs.popupMenu.$el.style.top = posY + "px";
|
|
this.$refs.popupMenu.$el.style.left = posX + "px";
|
|
this.$refs.popupMenu.$el.style.opacity = 1;
|
|
} catch (err) {
|
|
setTimeout(() => {
|
|
this.$refs.popupMenu.$el.style.top = posY + "px";
|
|
this.$refs.popupMenu.$el.style.left = posX + "px";
|
|
this.$refs.popupMenu.$el.style.opacity = 1;
|
|
}, 700);
|
|
}
|
|
},
|
|
openCommentForm() {
|
|
this.newComment = true;
|
|
},
|
|
|
|
/*
|
|
summary: save selected text
|
|
|
|
description: replace selected text with the new span.tcomment tag and then save it.
|
|
send a new request to api for saving the comment.
|
|
then update/replace paragraph content with newely created content.
|
|
then crawle all paragraphs for .tcomment ids.
|
|
then request api for paragraphs comments.
|
|
|
|
@fires when user clicked on comment popup save button.
|
|
@param {userComment} Html user comment.
|
|
@return void.
|
|
*/
|
|
saveSelectedTextComment(userComment) {
|
|
const url = tahrirApis.comments.addCommentToSelectedParag;
|
|
const replacedContent = this.replaceSelectedText();
|
|
|
|
const payload = {
|
|
content: replacedContent,
|
|
guid: this.paragraphId,
|
|
};
|
|
|
|
this.commentHttpService
|
|
.formDataRequest(url, payload)
|
|
.then((res) => {
|
|
this.newComment = false;
|
|
|
|
this.addComment(
|
|
{
|
|
text: userComment,
|
|
pid: this.globalGuid,
|
|
},
|
|
replacedContent
|
|
);
|
|
})
|
|
.catch((err) => {
|
|
this.mySwalToast({
|
|
html: err?.message,
|
|
});
|
|
})
|
|
.finally(() => (this.loading = false));
|
|
},
|
|
/*
|
|
summary: save comment
|
|
|
|
description:
|
|
send a new request to api for saving the comment.
|
|
then update/replace paragraph content with newely created content.
|
|
then crawle all paragraphs for .tcomment ids.
|
|
then request api for paragraphs comments.
|
|
|
|
@fires when saveSelectedTextComment method completed...
|
|
|
|
@param {text} String user comment.
|
|
@param {pid} String globalGuid.
|
|
@param {replacedContent} Html user comment.
|
|
|
|
@return void.
|
|
*/
|
|
addComment({ text, pid }, replacedContent) {
|
|
const payload = { text: JSON.stringify(text) };
|
|
const url = tahrirApis.comments.add + "/" + pid;
|
|
|
|
this.commentHttpService.formDataRequest(url, payload).then((res) => {
|
|
this.updateParagraphContentProperty(replacedContent);
|
|
|
|
this.crawlParagsForCommentId(this.localParagraphs).then((guidList) => {
|
|
this.getComments(guidList);
|
|
});
|
|
|
|
this.mySwalToast({
|
|
html: res.message,
|
|
});
|
|
});
|
|
},
|
|
/*
|
|
summary: update paragraph content property
|
|
|
|
description: update paragraph old content property with updated content.
|
|
|
|
@fires when addComment method completed...
|
|
|
|
@param {replacedContent} Html user comment.
|
|
|
|
@return void.
|
|
*/
|
|
updateParagraphContentProperty(replacedContent) {
|
|
this.localParagraphs.forEach((pars) => {
|
|
if (pars.id == this.paragraphParentId.slice(7))
|
|
pars.content = replacedContent;
|
|
});
|
|
},
|
|
|
|
/*
|
|
summary: update new comment form position
|
|
|
|
description: update position of new comment form when scrolling.
|
|
|
|
@fires when user scroll
|
|
|
|
@param {event} event window scroll event.
|
|
|
|
@return void.
|
|
*/
|
|
updateCommentFormTopPosition(event) {
|
|
// Find out how much (if any) user has scrolled
|
|
var scrollTop =
|
|
window.screenY !== undefined
|
|
? window.screenY
|
|
: (
|
|
document.documentElement ||
|
|
document.body.parentNode ||
|
|
document.body
|
|
).scrollTop;
|
|
|
|
const posY = event.clientY - 200 + scrollTop;
|
|
this.$refs.popupMenu._vnode.elm.style.top = posY + "px";
|
|
},
|
|
|
|
/*
|
|
summary: comment list
|
|
description: getting list of comments from the api.
|
|
|
|
@fires after page crawl for tcomment complete.
|
|
|
|
@param {array} guidList paragraph's comment ids.
|
|
|
|
@return void.
|
|
*/
|
|
|
|
getComments(guidList) {
|
|
let payload = {
|
|
limit: 50,
|
|
offset: 0,
|
|
refrence_id: this.$route.params.id,
|
|
entity_type_id: this.$route.meta.entityType,
|
|
entity_field_id: 1,
|
|
};
|
|
let url = repoApi.messages.update;
|
|
this.httpService1
|
|
.postRequest(url, payload)
|
|
.then((res) => {
|
|
this.mySwalToast({
|
|
html: res.message,
|
|
});
|
|
this.comments = res.data;
|
|
})
|
|
.catch((err) => {
|
|
this.mySwalToast({
|
|
html: err?.message,
|
|
});
|
|
})
|
|
.finally(() => {});
|
|
|
|
// let conversation = {
|
|
// limit: 50,
|
|
// offset: 0,
|
|
// refrence_id: this.id,
|
|
|
|
// };
|
|
// let url = repoApi.messages.list;
|
|
// this.httpService1.formDataRequest(url, conversation).then((res) => {
|
|
// this.comments=res.data
|
|
// if (res.data) {
|
|
// this.attachCommentsToParags(res.data);
|
|
|
|
// }
|
|
// });
|
|
|
|
// const payload = {
|
|
// pids: guidList,
|
|
// };
|
|
|
|
// this.commentHttpService.formDataRequest(tahrirApis.comments.documentComment, payload).then(
|
|
// (res) => {
|
|
// if (res.data)
|
|
// this.attachCommentsToParags(res.data);
|
|
// }
|
|
// );
|
|
},
|
|
/*
|
|
summary: attach comments to paragraphs object
|
|
description: loop over paragraphs and find paragraphs that
|
|
its content property math the comment id catched from the api.
|
|
|
|
@fires after getComment method called.
|
|
|
|
@param {object}
|
|
|
|
@return void.
|
|
*/
|
|
attachCommentsToParags(comments) {
|
|
try {
|
|
this.localParagraphs.forEach((parag) => {
|
|
const commentList = [];
|
|
|
|
Object.keys(comments).forEach((value) => {
|
|
if (parag.content.includes(value))
|
|
commentList.push(comments[value]);
|
|
});
|
|
this.$set(parag, "comments", commentList);
|
|
});
|
|
} catch (err) {
|
|
this.comments = comments;
|
|
}
|
|
|
|
this.fetchingData = false;
|
|
},
|
|
|
|
/*
|
|
summary: replace selected text with new span.
|
|
description: find the parent paragraph with its refs and
|
|
then replace the selected text with new span.
|
|
|
|
@fires when saveSelectedTextComment method called.
|
|
|
|
@return Html.
|
|
*/
|
|
replaceSelectedText() {
|
|
const text = decodeURIComponent(this.selectedText);
|
|
this.globalGuid = this.newGuid();
|
|
const replacementTag = `<span id="${this.globalGuid}" class="tcomment">${text}</span>`;
|
|
const refContent = this.$refs[this.paragraphParentId][0];
|
|
refContent.innerHTML = refContent.innerHTML.replace(text, replacementTag);
|
|
|
|
return refContent.innerHTML;
|
|
},
|
|
|
|
closeCommentForm() {
|
|
this.newComment = false;
|
|
},
|
|
|
|
/*
|
|
summary: crawl paragraphs for .tcomment.
|
|
description: crawl paragraph fot .tcomment tags and getting its id.
|
|
|
|
@fires when addComment method called.
|
|
|
|
@return Html.
|
|
*/
|
|
async crawlParagsForCommentId(pars) {
|
|
return await pars
|
|
.map((par) => {
|
|
if (par?.content.includes("tcomment"))
|
|
return this.geCommenttIds(par.content);
|
|
})
|
|
.filter((item) => item)
|
|
.join(",");
|
|
},
|
|
|
|
/*
|
|
summary: create unique id.
|
|
|
|
@fires when crawlParagsForCommentId method called.
|
|
|
|
@return string.
|
|
*/
|
|
newGuid() {
|
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
|
/[xy]/g,
|
|
function (c) {
|
|
var r = (Math.random() * 16) | 0,
|
|
v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
return v.toString(16);
|
|
}
|
|
);
|
|
},
|
|
|
|
/*
|
|
summary: separate spans id property..
|
|
|
|
@fires when crawlParagsForCommentId method called.
|
|
|
|
@return string.
|
|
*/
|
|
|
|
geCommenttIds(content) {
|
|
var ids = "";
|
|
var regex =
|
|
/\<span id=\\{0,1}\"([a-z0-9-]*?)\\{0,1}\" class=\\{0,1}\"tcomment\\{0,1}\".*?\>/g;
|
|
var m = regex.exec(content);
|
|
while (m !== null) {
|
|
if (m.index === regex.lastIndex) {
|
|
regex.lastIndex++;
|
|
}
|
|
if (ids != "") ids += ",";
|
|
ids += m[1];
|
|
m = regex.exec(content);
|
|
}
|
|
|
|
return ids;
|
|
},
|
|
|
|
handleScroll(event) {
|
|
// Any code to be executed when the window is scrolled
|
|
},
|
|
|
|
/*
|
|
summary: hide/show other paragraphs comments.
|
|
description: when user clicked on comment, hide other
|
|
comments and add active class to .tcomment tag in the paragraph
|
|
|
|
@fires when user open/close the comments.
|
|
|
|
@param {object} paragraph
|
|
@param {Number} commentIndex
|
|
|
|
@return void.
|
|
*/
|
|
|
|
hideOtherComments({ paragraph, commentIndex }) {
|
|
const _this = this;
|
|
|
|
_this.localParagraphs.forEach((par) => {
|
|
// parse other paragraphs
|
|
if (par.id != paragraph.id) {
|
|
if (par.comments?.length) {
|
|
par.comments.forEach((com, index) => {
|
|
const res = com.isShow == undefined ? false : !com.isShow;
|
|
_this.$set(par.comments[index], "isShow", res);
|
|
});
|
|
}
|
|
}
|
|
// parse selected paragraph
|
|
else {
|
|
if (par.comments?.length) {
|
|
par.comments.forEach((com, index) => {
|
|
// hide sibling comments in the active paragraph.
|
|
if (index != commentIndex) {
|
|
const res = com.isShow == undefined ? false : !com.isShow;
|
|
_this.$set(par.comments[index], "isShow", res);
|
|
}
|
|
// toggle paragraph .tcomment class
|
|
else {
|
|
Array.from(
|
|
_this.$refs["parent-" + par.id][0].children[0].children
|
|
).forEach((child) => {
|
|
if (child.id == com[0].pid) {
|
|
child.classList.toggle("active");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
removSpan(comment) {
|
|
const spanTag = document.getElementsById(comment.pid);
|
|
const rawText = spanTag.innerHTML;
|
|
|
|
this.paragraph.content = this.paragraph.content.replace(spanTag, rawText);
|
|
return this.paragraph.content;
|
|
},
|
|
|
|
saveChangeSelectedTextComment(userComment) {
|
|
const url = tahrirApis.comments.addCommentToSelectedParag;
|
|
const replacedContent = this.removSpan();
|
|
|
|
const payload = {
|
|
content: replacedContent,
|
|
guid: this.paragraphId,
|
|
};
|
|
|
|
ApiService.formData(url, payload)
|
|
.then((res) => {
|
|
this.newComment = false;
|
|
|
|
this.addComment(
|
|
{
|
|
text: userComment,
|
|
pid: this.globalGuid,
|
|
},
|
|
replacedContent
|
|
);
|
|
})
|
|
.catch((err) => {
|
|
this.mySwalToast({
|
|
html: err?.message,
|
|
});
|
|
})
|
|
.finally(() => (this.loading = false));
|
|
},
|
|
|
|
// #region comments link form methods
|
|
replaceSelectedText(linkText) {
|
|
const text = decodeURIComponent(this.selectedText);
|
|
this.globalGuid = this.newGuid();
|
|
const replacementTag = `<a id="${this.globalGuid}" name="${this.globalGuid}" href="${linkText}" title="${linkText}" target="_blank" class="c-link tlink">${text}</a>`;
|
|
const refContent = this.parentEl;
|
|
refContent.innerHTML = refContent.innerHTML.replace(text, replacementTag);
|
|
const sectionContent = refContent.innerHTML;
|
|
return sectionContent;
|
|
},
|
|
getSelectionParentElement() {
|
|
var parentEl = null,
|
|
sel;
|
|
if (window.getSelection) {
|
|
sel = window.getSelection();
|
|
if (sel.rangeCount) {
|
|
parentEl = sel.getRangeAt(0).commonAncestorContainer;
|
|
if (parentEl.nodeType != 1) {
|
|
parentEl = parentEl.parentNode;
|
|
}
|
|
}
|
|
} else if ((sel = document.selection) && sel.type != "Control") {
|
|
parentEl = sel.createRange().parentElement();
|
|
}
|
|
return parentEl;
|
|
},
|
|
saveLink(linkText = null) {
|
|
//چون از جهت کپی شده ، اینجا خطا دارد و تست و بازبینی باید بشود
|
|
let parnetId = this.parentEl.id;
|
|
let keyName = parnetId.replace("section-", "");
|
|
const formData = {
|
|
[keyName]: this.replaceSelectedText(linkText),
|
|
};
|
|
let url = `public/edit/${this.entity?.id}/${keyName}`;
|
|
this.httpService.postRequest(url, formData).then((response) => {});
|
|
},
|
|
closeCommentForm() {
|
|
this.newComment = false;
|
|
},
|
|
createPopup(event, formRefName = "popupMenu") {
|
|
this.openCommentForm(formRefName);
|
|
this.parentEl = this.getSelectionParentElement();
|
|
const posX = event.clientX;
|
|
const posY = event.clientY;
|
|
|
|
try {
|
|
this.$refs[formRefName].$el.style.top = posY + "px";
|
|
this.$refs[formRefName].$el.style.left = posX + "px";
|
|
this.$refs[formRefName].$el.style.opacity = 1;
|
|
} catch (err) {
|
|
setTimeout(() => {
|
|
this.$refs[formRefName].$el.style.top = posY + "px";
|
|
this.$refs[formRefName].$el.style.left = posX + "px";
|
|
this.$refs[formRefName].$el.style.opacity = 1;
|
|
}, 700);
|
|
}
|
|
},
|
|
openCommentForm(formRefName = "popupMenu") {
|
|
if (formRefName == "popupMenu") this.newComment = true;
|
|
else this.newLink = true;
|
|
},
|
|
closeCommentForm(formRefName = "popupMenu") {
|
|
if (formRefName == "popupMenu") this.newComment = false;
|
|
else this.newLink = false;
|
|
},
|
|
localSaveSelectedTextComment(userComment) {
|
|
this.addToConversation(userComment);
|
|
},
|
|
addToConversation(res) {
|
|
let conversation = {
|
|
text: res,
|
|
refrence_id: this.entity?.id,
|
|
entity_field_id: this.sections.find(
|
|
(theme) => theme.key == this.propertyName
|
|
).id,
|
|
};
|
|
|
|
let url = repoApi.messages.create;
|
|
|
|
this.chatHttpService.postRequest(url, conversation).then((rese) => {
|
|
//this.getSectionsLastComment();
|
|
// this.getEntityQModelInfo();
|
|
});
|
|
},
|
|
getComments(entity_field_id = 1) {
|
|
let payload = {
|
|
limit: 100,
|
|
offset: 0,
|
|
refrence_id: this.rootCommentId,
|
|
entity_field_id,
|
|
};
|
|
|
|
let url = repoApi.messages.list;
|
|
this.chatHttpService
|
|
.postRequest(url, payload)
|
|
.then((res) => {
|
|
this.comments = res.data;
|
|
})
|
|
.catch((err) => {
|
|
this.mySwalToast({
|
|
html: err?.message,
|
|
});
|
|
})
|
|
.finally(() => {});
|
|
},
|
|
getSectionsLastComment() {
|
|
const vm = this;
|
|
let url = repoApi.messages.sectionLastComment;
|
|
let payload = {
|
|
refrence_id: this.rootCommentId,
|
|
};
|
|
|
|
this.chatHttpService.postRequest(url, payload).then((res) => {
|
|
let comments = {};
|
|
|
|
res.data.forEach((lastCom) => {
|
|
let themeItem = vm.sections.find(
|
|
(theme) => theme.id == lastCom.entity_field_id
|
|
);
|
|
|
|
if (themeItem)
|
|
comments[`${vm.rootCommentId}_${themeItem.key}`] = [lastCom];
|
|
});
|
|
|
|
this.comments = comments;
|
|
this.showComments = true;
|
|
});
|
|
},
|
|
updateComment() {
|
|
const vm = this;
|
|
|
|
let payload = {
|
|
limit: 50,
|
|
offset: 0,
|
|
refrence_id: this.rootCommentId,
|
|
entity_field_id: this.sections.find(
|
|
(section) => section.key == this.propertyName
|
|
).id,
|
|
};
|
|
|
|
let url = repoApi.messages.sectionLastComment;
|
|
this.chatHttpService.postRequest(url, payload).then((res) => {
|
|
this.mySwalToast({
|
|
html: res.message,
|
|
});
|
|
|
|
this.comments = res.data;
|
|
|
|
res.data.forEach((lastCom) => {
|
|
let themeItem = vm.sections.find(
|
|
(section) => section.id == lastCom.entity_field_id
|
|
);
|
|
|
|
if (themeItem)
|
|
vm.$set(vm.comments, `${vm.rootCommentId}_${themeItem.key}`, [
|
|
lastCom,
|
|
]);
|
|
});
|
|
|
|
this.counter++;
|
|
});
|
|
},
|
|
openNewCommentModal({
|
|
event,
|
|
propertyName,
|
|
formRefName = "popupMenu",
|
|
title = undefined,
|
|
}) {
|
|
this.propertyName = propertyName;
|
|
if (title) this.selectedText = title;
|
|
else
|
|
this.selectedText =
|
|
typeof this.entity[propertyName] == "string"
|
|
? this.entity[propertyName]
|
|
: "بدون عنوان";
|
|
this.createPopup(event, formRefName);
|
|
},
|
|
closeNewCommentModal() {
|
|
this.selectedText = "";
|
|
this.newComment = false;
|
|
this.showComments = false;
|
|
},
|
|
hideOtherComments({ propertyName }) {
|
|
this.propertyName = propertyName;
|
|
this.showComments = !this.showComments;
|
|
},
|
|
|
|
// #endregion
|
|
},
|
|
};
|