diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py
index f5d758d4de..2d92035be4 100644
--- a/frappe/core/doctype/communication/communication.py
+++ b/frappe/core/doctype/communication/communication.py
@@ -110,6 +110,7 @@ class Communication(Document):
recipients += self.get_commentors()
recipients += [s.strip() for s in self.recipients.split(",")]
recipients += self.get_assignees()
+ recipients += self.get_starrers()
recipients = filter(lambda e: e and e!="Administrator", list(set(recipients)))
# remove unsubscribed recipients
@@ -118,6 +119,10 @@ class Communication(Document):
return recipients
+ def get_starrers(self):
+ """Return list of users who have starred this document."""
+ return self.get_parent_doc().get_starred_by()
+
def get_earlier_participants(self):
return frappe.db.sql("""
select distinct sender
diff --git a/frappe/model/document.py b/frappe/model/document.py
index 7778b48eb4..cc09fca6c6 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -8,7 +8,7 @@ from frappe.utils import flt, cint, cstr, now, get_datetime_str
from frappe.model.base_document import BaseDocument, get_controller
from frappe.model.naming import set_new_name
from werkzeug.exceptions import NotFound, Forbidden
-import hashlib
+import hashlib, json
# once_only validation
# methods
@@ -662,3 +662,10 @@ class Document(BaseDocument):
def get_signature(self):
"""Returns signature (hash) for private URL."""
return hashlib.sha224(get_datetime_str(self.creation)).hexdigest()
+
+ def get_starred_by(self):
+ starred_by = getattr(self, "_starred_by", None)
+ if starred_by:
+ return json.dumps(starred_by)
+ else:
+ return []
diff --git a/frappe/public/css/common.css b/frappe/public/css/common.css
index f90c804451..d277a1cd23 100644
--- a/frappe/public/css/common.css
+++ b/frappe/public/css/common.css
@@ -197,3 +197,13 @@ a.badge-hover:active .badge {
#freeze.in {
opacity: 0.5;
}
+a.no-decoration {
+ text-decoration: none;
+ color: inherit;
+}
+a.no-decoration:hover,
+a.no-decoration:focus,
+a.no-decoration:active {
+ text-decoration: none;
+ color: inherit;
+}
diff --git a/frappe/public/css/desk.css b/frappe/public/css/desk.css
index 3d8c1faad1..76c72eeb03 100644
--- a/frappe/public/css/desk.css
+++ b/frappe/public/css/desk.css
@@ -197,6 +197,16 @@ a.badge-hover:active .badge {
#freeze.in {
opacity: 0.5;
}
+a.no-decoration {
+ text-decoration: none;
+ color: inherit;
+}
+a.no-decoration:hover,
+a.no-decoration:focus,
+a.no-decoration:active {
+ text-decoration: none;
+ color: inherit;
+}
.nav-pills a,
.nav-pills a:hover {
border-bottom: none;
diff --git a/frappe/public/css/website.css b/frappe/public/css/website.css
index 13a241893d..209f3d924f 100644
--- a/frappe/public/css/website.css
+++ b/frappe/public/css/website.css
@@ -197,6 +197,16 @@ a.badge-hover:active .badge {
#freeze.in {
opacity: 0.5;
}
+a.no-decoration {
+ text-decoration: none;
+ color: inherit;
+}
+a.no-decoration:hover,
+a.no-decoration:focus,
+a.no-decoration:active {
+ text-decoration: none;
+ color: inherit;
+}
html {
min-height: 100%;
}
@@ -594,16 +604,6 @@ textarea {
.post-content img {
margin: 10px 0px;
}
-a.no-decoration {
- text-decoration: none;
- color: inherit;
-}
-a.no-decoration:hover,
-a.no-decoration:focus,
-a.no-decoration:active {
- text-decoration: none;
- color: inherit;
-}
a.active {
pointer-events: none;
cursor: default;
diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js
index 63862d1d94..59cd055bb4 100644
--- a/frappe/public/js/frappe/form/toolbar.js
+++ b/frappe/public/js/frappe/form/toolbar.js
@@ -14,6 +14,7 @@ frappe.ui.form.Toolbar = Class.extend({
this.page.clear_user_actions();
this.show_title_as_dirty();
this.set_primary_action();
+ this.refresh_star();
if(this.frm.meta.hide_toolbar) {
this.page.hide_menu();
@@ -21,9 +22,11 @@ frappe.ui.form.Toolbar = Class.extend({
if(this.frm.doc.__islocal) {
this.page.hide_menu();
this.print_icon && this.print_icon.addClass("hide");
+ this.star_icon.addClass("hide");
} else {
this.page.show_menu();
this.print_icon && this.print_icon.removeClass("hide");
+ this.star_icon.removeClass("hide");
}
}
},
@@ -56,6 +59,10 @@ frappe.ui.form.Toolbar = Class.extend({
this.page.clear_indicator();
}
},
+ refresh_star: function() {
+ this.star_icon.toggleClass("text-extra-muted not-starred", !frappe.ui.is_starred(this.frm.doc))
+ .attr("data-doctype", this.frm.doctype).attr("data-name", this.frm.doc.name);
+ },
make_menu: function() {
var me = this;
var p = this.frm.perm[0];
@@ -69,6 +76,11 @@ frappe.ui.form.Toolbar = Class.extend({
me.frm.print_doc();});
}
+ // star
+ this.star_icon = this.page.add_action_icon("icon-star", function() {
+ frappe.ui.toggle_star(me.star_icon, me.frm.doctype, me.frm.doc.name);
+ }).removeClass("text-muted").find(".icon-star").addClass("star-action");
+
// email
if(frappe.model.can_email(null, me.frm)) {
this.page.add_menu_item(__("Email"), function() {
diff --git a/frappe/public/js/frappe/list/list_item_subject.html b/frappe/public/js/frappe/list/list_item_subject.html
index f063d6a430..9477b32f42 100644
--- a/frappe/public/js/frappe/list/list_item_subject.html
+++ b/frappe/public/js/frappe/list/list_item_subject.html
@@ -3,7 +3,7 @@
{% } %}
{%= _title %}
diff --git a/frappe/public/js/frappe/ui/page.js b/frappe/public/js/frappe/ui/page.js
index 43d5e68d89..a58cd975bf 100644
--- a/frappe/public/js/frappe/ui/page.js
+++ b/frappe/public/js/frappe/ui/page.js
@@ -93,7 +93,7 @@ frappe.ui.Page = Class.extend({
},
add_action_icon: function(icon, click) {
- return $('')
+ return $('')
.appendTo(this.icon_group.removeClass("hide"))
.click(click);
},
diff --git a/frappe/public/js/frappe/ui/star.js b/frappe/public/js/frappe/ui/star.js
index b8bad1041b..01a06b6a4a 100644
--- a/frappe/public/js/frappe/ui/star.js
+++ b/frappe/public/js/frappe/ui/star.js
@@ -1,6 +1,15 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
+frappe.ui.is_starred = function(doc) {
+ var starred = doc._starred_by;
+ if(starred) {
+ starred = JSON.parse(starred);
+ return starred.indexOf(user)===-1 ? false : true;
+ }
+ return false;
+}
+
frappe.ui.toggle_star = function($btn, doctype, name) {
var add = $btn.hasClass("not-starred") ? "Yes" : "No";
frappe.call({
@@ -14,7 +23,8 @@ frappe.ui.toggle_star = function($btn, doctype, name) {
callback: function(r) {
if(!r.exc) {
// update in all local-buttons
- var action_buttons = $(".star-action[data-name='"+ name.replace(/"/g, '\"') +"']");
+ var action_buttons = $('.star-action[data-name="'+ name.replace(/"/g, '\"')
+ +'"][data-doctype="'+ doctype.replace(/"/g, '\"')+'"]');
if(add==="Yes") {
action_buttons.removeClass("not-starred").removeClass("text-extra-muted");
diff --git a/frappe/public/less/common.less b/frappe/public/less/common.less
index 7208fb3518..f199f9d328 100644
--- a/frappe/public/less/common.less
+++ b/frappe/public/less/common.less
@@ -209,3 +209,15 @@ a.badge-hover& {
#freeze.in {
opacity: 0.5;
}
+
+a.no-decoration& {
+ text-decoration: none;
+ color: inherit;
+
+ &:hover,
+ &:focus,
+ &:active {
+ text-decoration: none;
+ color: inherit;
+ }
+}
diff --git a/frappe/public/less/website.less b/frappe/public/less/website.less
index 620268327b..2549a7dd7e 100644
--- a/frappe/public/less/website.less
+++ b/frappe/public/less/website.less
@@ -301,18 +301,6 @@ textarea {
margin: 10px 0px;
}
-a.no-decoration& {
- text-decoration: none;
- color: inherit;
-
- &:hover,
- &:focus,
- &:active {
- text-decoration: none;
- color: inherit;
- }
-}
-
a.active {
pointer-events: none;
cursor: default;