feat: Shareable link for comments and communications

- Also, highlight comment/communication that has been shared.
This commit is contained in:
Suraj Shetty 2021-10-07 21:50:08 +05:30
parent 3537316a2a
commit f1c5fc4fe6
9 changed files with 84 additions and 19 deletions

View file

@ -97,9 +97,13 @@ class BaseTimeline {
}
timeline_item.append(`<div class="timeline-content ${item.is_card ? 'frappe-card' : ''}">`);
timeline_item.find('.timeline-content').append(item.content);
let timeline_content = timeline_item.find('.timeline-content');
timeline_content.append(item.content);
if (!item.hide_timestamp && !item.is_card) {
timeline_item.find('.timeline-content').append(`<span> - ${comment_when(item.creation)}</span>`);
timeline_content.append(`<span> - ${comment_when(item.creation)}</span>`);
}
if (item.id) {
timeline_content.attr("id", item.id);
}
return timeline_item;
}

View file

@ -96,6 +96,7 @@ class FormTimeline extends BaseTimeline {
render_timeline_items() {
super.render_timeline_items();
this.set_document_info();
frappe.utils.bind_actions_with_object(this.timeline_items_wrapper, this);
}
set_document_info() {
@ -179,6 +180,7 @@ class FormTimeline extends BaseTimeline {
is_card: true,
content: this.get_communication_timeline_content(communication),
doctype: "Communication",
id: `communication-${communication.name}`,
name: communication.name
});
});
@ -246,6 +248,7 @@ class FormTimeline extends BaseTimeline {
creation: comment.creation,
is_card: true,
doctype: "Comment",
id: `comment-${comment.name}`,
name: comment.name,
content: this.get_comment_timeline_content(comment),
};
@ -394,7 +397,7 @@ class FormTimeline extends BaseTimeline {
}
setup_reply(communication_box, communication_doc) {
let actions = communication_box.find('.actions');
let actions = communication_box.find('.custom-actions');
let reply = $(`<a class="action-btn reply">${frappe.utils.icon('reply', 'md')}</a>`).click(() => {
this.compose_mail(communication_doc);
});
@ -446,14 +449,16 @@ class FormTimeline extends BaseTimeline {
let edit_wrapper = $(`<div class="comment-edit-box">`).hide();
let edit_box = this.make_editable(edit_wrapper);
let content_wrapper = comment_wrapper.find('.content');
let delete_button = $();
let more_actions_wrapper = comment_wrapper.find('.more-actions');
if (frappe.model.can_delete("Comment")) {
delete_button = $(`
<button class="btn btn-link action-btn">
${frappe.utils.icon('close', 'sm')}
</button>
const delete_option = $(`
<li>
<a class="dropdown-item">
${__("Delete")}
</a>
</li>
`).click(() => this.delete_comment(doc.name));
more_actions_wrapper.find('.dropdown-menu').append(delete_option);
}
let dismiss_button = $(`
@ -493,15 +498,14 @@ class FormTimeline extends BaseTimeline {
edit_button.toggle_edit_mode = () => {
edit_button.edit_mode = !edit_button.edit_mode;
edit_button.text(edit_button.edit_mode ? __('Save') : __('Edit'));
delete_button.toggle(!edit_button.edit_mode);
more_actions_wrapper.toggle(!edit_button.edit_mode);
dismiss_button.toggle(edit_button.edit_mode);
edit_wrapper.toggle(edit_button.edit_mode);
content_wrapper.toggle(!edit_button.edit_mode);
};
comment_wrapper.find('.actions').append(edit_button);
comment_wrapper.find('.actions').append(dismiss_button);
comment_wrapper.find('.actions').append(delete_button);
let actions_wrapper = comment_wrapper.find('.custom-actions');
actions_wrapper.append(edit_button);
actions_wrapper.append(dismiss_button);
}
make_editable(container) {
@ -559,6 +563,14 @@ class FormTimeline extends BaseTimeline {
});
});
}
copy_link(ev) {
let doc_link = frappe.urllib.get_full_url(
frappe.utils.get_form_link(this.frm.doctype, this.frm.docname)
);
let element_id = $(ev.currentTarget).closest(".timeline-content").attr("id");
frappe.utils.copy_to_clipboard(`${doc_link}#${element_id}`);
}
}
export default FormTimeline;

View file

@ -480,7 +480,11 @@ frappe.ui.form.Form = class FrappeForm {
this.layout.show_empty_form_message();
}
this.scroll_to_element();
frappe.after_ajax(() => {
$(document).ready(() => {
this.scroll_to_element();
});
});
}
set_first_tab_as_active() {
@ -598,6 +602,8 @@ frappe.ui.form.Form = class FrappeForm {
this.validate_form_action(save_action, resolve);
var after_save = function(r) {
// to remove hash from URL to avoid scroll after save
history.replaceState(null, null, ' ');
if(!r.exc) {
if (["Save", "Update", "Amend"].indexOf(save_action)!==-1) {
frappe.utils.play_sound("click");
@ -1195,6 +1201,8 @@ frappe.ui.form.Form = class FrappeForm {
if (selector.length) {
frappe.utils.scroll_to(selector);
}
} else if (window.location.hash && $(window.location.hash).length) {
frappe.utils.scroll_to(window.location.hash, true, 200, null, null, true);
}
}

View file

@ -63,6 +63,20 @@
</svg>
</a>
{% } %}
<div class="custom-actions"></div>
<div class="more-actions">
<a type="button" class="action-btn"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<svg class="icon icon-sm">
<use xlink:href="#icon-dot-horizontal"></use>
</svg>
</a>
<ul class="dropdown-menu small">
<li>
<a class="dropdown-item" data-action="copy_link">{{ __('Copy Link') }}</a>
</li>
</ul>
</div>
</span>
</span>
<div class="content">

View file

@ -268,7 +268,8 @@ Object.assign(frappe.utils, {
</a></p>');
return content.html();
},
scroll_to: function(element, animate=true, additional_offset, element_to_be_scrolled, callback) {
scroll_to: function(element, animate=true, additional_offset,
element_to_be_scrolled, callback, highlight_element=false) {
if (frappe.flags.disable_auto_scroll) return;
element_to_be_scrolled = element_to_be_scrolled || $("html, body");
@ -291,11 +292,20 @@ Object.assign(frappe.utils, {
}
if (animate) {
element_to_be_scrolled.animate({ scrollTop: scroll_top }).promise().then(callback);
element_to_be_scrolled.animate({
scrollTop: scroll_top
}, null, () => {
if (highlight_element) {
$(element).addClass('highlight');
document.addEventListener("click", function() {
$(element).removeClass('highlight');
}, {once: true});
}
callback && callback();
});
} else {
element_to_be_scrolled.scrollTop(scroll_top);
}
},
get_scroll_position: function(element, additional_offset) {
let header_offset = $(".navbar").height() + $(".page-head:visible").height();

View file

@ -209,6 +209,8 @@
--highlight-color: var(--gray-50);
--yellow-highlight-color: var(--yellow-50);
--highlight-shadow: 1px 1px 10px var(--blue-50), 0px 0px 4px var(--blue-600);
// Border Sizes
--border-radius-sm: 4px;
--border-radius: 6px;

View file

@ -75,6 +75,8 @@
--highlight-color: var(--gray-700);
--yellow-highlight-color: var(--yellow-700);
--highlight-shadow: 1px 1px 10px var(--blue-900), 0px 0px 4px var(--blue-500);
// input
--input-disabled-bg: none;

View file

@ -561,6 +561,19 @@ details > summary:focus {
display: none;
}
.highlight {
transition: 0.5s ease background-color;
box-shadow: var(--highlight-shadow) !important;
}
.dropdown-menu.small {
font-size: var(--text-sm);
min-width: 140px;
.dropdown-item {
padding: var(--padding-xs);
}
}
// REDESIGN TODO: Handling of broken images?
// img.no-image:before {
// .img-background();

View file

@ -117,7 +117,7 @@ $threshold: 34;
.actions {
display: flex;
> * {
> *:not(.indicator-pill) {
color: var(--text-muted);
}
}