@@ -388,6 +388,22 @@ def has_permission(doctype, ptype="read", doc=None, user=None, verbose=False): | |||||
import frappe.permissions | import frappe.permissions | ||||
return frappe.permissions.has_permission(doctype, ptype, doc, verbose=verbose, user=user) | return frappe.permissions.has_permission(doctype, ptype, doc, verbose=verbose, user=user) | ||||
def has_website_permission(doctype, ptype="read", doc=None, user=None, verbose=False): | |||||
"""Raises `frappe.PermissionError` if not permitted. | |||||
:param doctype: DocType for which permission is to be check. | |||||
:param ptype: Permission type (`read`, `write`, `create`, `submit`, `cancel`, `amend`). Default: `read`. | |||||
:param doc: Checks User permissions for given doc. | |||||
:param user: [optional] Check for given user. Default: current user.""" | |||||
if not user: user = session.user | |||||
for method in get_hooks("has_website_permission").get(doctype, []): | |||||
if not call(get_attr(method), doc=doc, ptype=ptype, user=user, verbose=verbose): | |||||
return False | |||||
return True | |||||
def is_table(doctype): | def is_table(doctype): | ||||
"""Returns True if `istable` property (indicating child Table) is set for given DocType.""" | """Returns True if `istable` property (indicating child Table) is set for given DocType.""" | ||||
tables = cache().get_value("is_table") | tables = cache().get_value("is_table") | ||||
@@ -29,6 +29,10 @@ web_include_css = [ | |||||
"assets/css/frappe-web.css", | "assets/css/frappe-web.css", | ||||
"website_theme.css" | "website_theme.css" | ||||
] | ] | ||||
website_route_rules = [ | |||||
{"from_route": "/blog", "to_route": "Blog Post"}, | |||||
{"from_route": "/blog/<category>", "to_route": "Blog Post"} | |||||
] | |||||
write_file_keys = ["file_url", "file_name"] | write_file_keys = ["file_url", "file_name"] | ||||
@@ -432,8 +432,13 @@ class BaseDocument(object): | |||||
def get_formatted(self, fieldname, doc=None, currency=None): | def get_formatted(self, fieldname, doc=None, currency=None): | ||||
from frappe.utils.formatters import format_value | from frappe.utils.formatters import format_value | ||||
return format_value(self.get(fieldname), self.meta.get_field(fieldname), | |||||
doc=doc or self, currency=currency) | |||||
df = self.meta.get_field(fieldname) | |||||
if not df and fieldname in default_fields: | |||||
from frappe.model.meta import get_default_df | |||||
df = get_default_df(fieldname) | |||||
return format_value(self.get(fieldname), df=df, doc=doc or self, currency=currency) | |||||
def is_print_hide(self, fieldname, for_print=True): | def is_print_hide(self, fieldname, for_print=True): | ||||
"""Returns true if fieldname is to be hidden for print. | """Returns true if fieldname is to be hidden for print. | ||||
@@ -23,7 +23,7 @@ class DatabaseQuery(object): | |||||
def execute(self, query=None, fields=None, filters=None, or_filters=None, | def execute(self, query=None, fields=None, filters=None, or_filters=None, | ||||
docstatus=None, group_by=None, order_by=None, limit_start=False, | docstatus=None, group_by=None, order_by=None, limit_start=False, | ||||
limit_page_length=False, as_list=False, with_childnames=False, debug=False, | |||||
limit_page_length=None, as_list=False, with_childnames=False, debug=False, | |||||
ignore_permissions=False, user=None): | ignore_permissions=False, user=None): | ||||
if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user): | if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user): | ||||
raise frappe.PermissionError, self.doctype | raise frappe.PermissionError, self.doctype | ||||
@@ -36,7 +36,7 @@ class DatabaseQuery(object): | |||||
self.group_by = group_by | self.group_by = group_by | ||||
self.order_by = order_by | self.order_by = order_by | ||||
self.limit_start = 0 if (limit_start is False) else cint(limit_start) | self.limit_start = 0 if (limit_start is False) else cint(limit_start) | ||||
self.limit_page_length = 20 if (limit_page_length is False) else cint(limit_page_length) | |||||
self.limit_page_length = cint(limit_page_length) if limit_page_length else None | |||||
self.with_childnames = with_childnames | self.with_childnames = with_childnames | ||||
self.debug = debug | self.debug = debug | ||||
self.as_list = as_list | self.as_list = as_list | ||||
@@ -91,6 +91,7 @@ class Meta(Document): | |||||
if not self._fields: | if not self._fields: | ||||
for f in self.get("fields"): | for f in self.get("fields"): | ||||
self._fields[f.fieldname] = f | self._fields[f.fieldname] = f | ||||
return self._fields.get(fieldname) | return self._fields.get(fieldname) | ||||
def get_label(self, fieldname): | def get_label(self, fieldname): | ||||
@@ -306,3 +307,17 @@ def clear_cache(doctype=None): | |||||
frappe.cache().delete_keys(p + ":") | frappe.cache().delete_keys(p + ":") | ||||
frappe.cache().delete_value("is_table") | frappe.cache().delete_value("is_table") | ||||
def get_default_df(fieldname): | |||||
if fieldname in default_fields: | |||||
if fieldname in ("creation", "modified"): | |||||
return frappe._dict( | |||||
fieldname = fieldname, | |||||
fieldtype = "Datetime" | |||||
) | |||||
else: | |||||
return frappe._dict( | |||||
fieldname = fieldname, | |||||
fieldtype = "Data" | |||||
) |
@@ -1,8 +1,10 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe | import frappe | ||||
from frappe import _ | from frappe import _ | ||||
from frappe.utils import cint | |||||
def execute(): | def execute(): | ||||
frappe.reload_doctype("Website Settings") | |||||
frappe.reload_doc("website", "doctype", "website_theme") | frappe.reload_doc("website", "doctype", "website_theme") | ||||
frappe.reload_doc("website", "website_theme", "standard") | frappe.reload_doc("website", "website_theme", "standard") | ||||
migrate_style_settings() | migrate_style_settings() | ||||
@@ -20,8 +22,7 @@ def migrate_style_settings(): | |||||
map_color_fields(style_settings, website_theme) | map_color_fields(style_settings, website_theme) | ||||
map_other_fields(style_settings, website_theme) | map_other_fields(style_settings, website_theme) | ||||
website_settings = frappe.get_doc("Website Settings", "Website Settings") | |||||
website_theme.no_sidebar = website_settings.no_sidebar | |||||
website_theme.no_sidebar = cint(frappe.db.get_single_value("Website Settings", "no_sidebar")) | |||||
website_theme.save() | website_theme.save() | ||||
website_theme.use_theme() | website_theme.use_theme() | ||||
@@ -1,44 +1,44 @@ | |||||
.avatar { | .avatar { | ||||
display: inline-block; | |||||
vertical-align: middle; | |||||
overflow: hidden; | |||||
width: 50px; | |||||
height: 50px; | |||||
display: inline-block; | |||||
vertical-align: middle; | |||||
overflow: hidden; | |||||
width: 50px; | |||||
height: 50px; | |||||
} | } | ||||
.avatar img { | .avatar img { | ||||
width: 100%; | |||||
height: auto; | |||||
border-radius: 4px; | |||||
width: 100%; | |||||
height: auto; | |||||
border-radius: 4px; | |||||
} | } | ||||
.avatar-empty { | .avatar-empty { | ||||
border: 1px dashed #d1d8dd; | |||||
border: 1px dashed #d1d8dd; | |||||
} | } | ||||
.avatar-small { | .avatar-small { | ||||
margin-right: 5px; | |||||
width: 24px; | |||||
height: 24px; | |||||
margin-right: 5px; | |||||
width: 24px; | |||||
height: 24px; | |||||
} | } | ||||
.avatar-medium { | .avatar-medium { | ||||
margin-right: 5px; | |||||
width: 36px; | |||||
height: 36px; | |||||
margin-right: 5px; | |||||
width: 36px; | |||||
height: 36px; | |||||
} | } | ||||
.avatar-large { | .avatar-large { | ||||
margin-right: 10px; | |||||
width: 72px; | |||||
height: 72px; | |||||
margin-right: 10px; | |||||
width: 72px; | |||||
height: 72px; | |||||
} | } | ||||
.avatar-xs { | .avatar-xs { | ||||
margin-right: 3px; | |||||
margin-top: -2px; | |||||
width: 17px; | |||||
height: 17px; | |||||
border: none; | |||||
border-radius: 3px; | |||||
margin-right: 3px; | |||||
margin-top: -2px; | |||||
width: 17px; | |||||
height: 17px; | |||||
border: none; | |||||
border-radius: 3px; | |||||
} | |||||
.avatar-text { | |||||
display: inline; | |||||
width: 100%; | |||||
height: 0; | |||||
padding-bottom: 100%; | |||||
} | } |
@@ -0,0 +1,145 @@ | |||||
a { | |||||
cursor: pointer; | |||||
} | |||||
a, | |||||
a:hover, | |||||
a:active, | |||||
a:focus { | |||||
outline: 0; | |||||
} | |||||
img { | |||||
max-width: 100%; | |||||
} | |||||
.text-color { | |||||
color: #36414c !important; | |||||
} | |||||
.text-muted { | |||||
color: #8d99a6 !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: #d1d8dd !important; | |||||
} | |||||
a, | |||||
.badge, | |||||
.ui-menu .ui-menu-item { | |||||
-webkit-transition: 0.2s; | |||||
-o-transition: 0.2s; | |||||
transition: 0.2s; | |||||
} | |||||
.btn { | |||||
-webkit-transition: background-color 0.2s; | |||||
-o-transition: background-color 0.2s; | |||||
transition: background-color 0.2s; | |||||
} | |||||
a.disabled, | |||||
a.disabled:hover { | |||||
color: #888; | |||||
cursor: default; | |||||
text-decoration: none; | |||||
} | |||||
a.grey, | |||||
.sidebar-section a, | |||||
.nav-pills a, | |||||
.control-value a, | |||||
.data-row a { | |||||
color: inherit; | |||||
border-bottom: 1px solid transparent; | |||||
margin-bottom: 0.4em; | |||||
} | |||||
a.grey:hover, | |||||
.sidebar-section a:hover, | |||||
.nav-pills a:hover, | |||||
.control-value a:hover, | |||||
.data-row a:hover { | |||||
border-bottom: 1px solid #212a33; | |||||
color: #212a33; | |||||
} | |||||
a.text-muted, | |||||
a.text-extra-muted { | |||||
border-bottom: 1px solid transparent; | |||||
} | |||||
a.text-muted:hover, | |||||
a.text-muted:focus, | |||||
a.text-extra-muted:hover, | |||||
a.text-extra-muted:focus { | |||||
color: inherit; | |||||
border-bottom: 1px solid #8d99a6; | |||||
} | |||||
.text-ellipsis { | |||||
white-space: nowrap; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
} | |||||
.bold, | |||||
.strong { | |||||
font-weight: bold; | |||||
} | |||||
kbd { | |||||
color: inherit; | |||||
background-color: #f0f4f7; | |||||
} | |||||
.padding { | |||||
padding: 15px; | |||||
} | |||||
.btn [class^="icon-"], | |||||
.nav [class^="icon-"], | |||||
.btn [class*=" icon-"], | |||||
.nav [class*=" icon-"] { | |||||
display: inline-block; | |||||
} | |||||
.dropdown-menu > li > a { | |||||
padding: 14px; | |||||
} | |||||
.dropdown-menu { | |||||
min-width: 200px; | |||||
padding: 0px; | |||||
font-size: 12px; | |||||
border-radius: 0px 0px 4px 4px; | |||||
} | |||||
.dropdown-menu .divider { | |||||
margin: 0px; | |||||
} | |||||
a.badge-hover:hover .badge, | |||||
a.badge-hover:focus .badge, | |||||
a.badge-hover:active .badge { | |||||
background-color: #D8DFE5; | |||||
} | |||||
.msgprint { | |||||
text-align: center; | |||||
} | |||||
.msgprint pre { | |||||
text-align: left; | |||||
} | |||||
.centered { | |||||
position: relative; | |||||
left: 50%; | |||||
transform: translate(-50%, 0); | |||||
-webkit-transform: translate(-50%, 0); | |||||
} | |||||
.border-top { | |||||
border-top: 1px solid #d1d8dd; | |||||
} | |||||
.border-bottom { | |||||
border-bottom: 1px solid #d1d8dd; | |||||
} | |||||
.border-left { | |||||
border-left: 1px solid #d1d8dd; | |||||
} | |||||
.border-right { | |||||
border-right: 1px solid #d1d8dd; | |||||
} | |||||
.border { | |||||
border: 1px solid #d1d8dd; | |||||
} | |||||
.close-inline { | |||||
font-size: 120%; | |||||
font-weight: bold; | |||||
line-height: 1; | |||||
cursor: pointer; | |||||
color: inherit; | |||||
display: inline-block; | |||||
} | |||||
.close-inline:hover, | |||||
.close-inline:focus { | |||||
text-decoration: none; | |||||
} |
@@ -1,9 +1,24 @@ | |||||
a { | |||||
cursor: pointer; | |||||
} | |||||
a, | a, | ||||
a:hover, | a:hover, | ||||
a:active, | a:active, | ||||
a:focus { | a:focus { | ||||
outline: 0; | outline: 0; | ||||
} | } | ||||
img { | |||||
max-width: 100%; | |||||
} | |||||
.text-color { | |||||
color: #36414c !important; | |||||
} | |||||
.text-muted { | |||||
color: #8d99a6 !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: #d1d8dd !important; | |||||
} | |||||
a, | a, | ||||
.badge, | .badge, | ||||
.ui-menu .ui-menu-item { | .ui-menu .ui-menu-item { | ||||
@@ -39,15 +54,6 @@ a.grey:hover, | |||||
border-bottom: 1px solid #212a33; | border-bottom: 1px solid #212a33; | ||||
color: #212a33; | color: #212a33; | ||||
} | } | ||||
.text-color { | |||||
color: #36414c !important; | |||||
} | |||||
.text-muted { | |||||
color: #8d99a6 !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: #d1d8dd !important; | |||||
} | |||||
a.text-muted, | a.text-muted, | ||||
a.text-extra-muted { | a.text-extra-muted { | ||||
border-bottom: 1px solid transparent; | border-bottom: 1px solid transparent; | ||||
@@ -59,6 +65,84 @@ a.text-extra-muted:focus { | |||||
color: inherit; | color: inherit; | ||||
border-bottom: 1px solid #8d99a6; | border-bottom: 1px solid #8d99a6; | ||||
} | } | ||||
.text-ellipsis { | |||||
white-space: nowrap; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
} | |||||
.bold, | |||||
.strong { | |||||
font-weight: bold; | |||||
} | |||||
kbd { | |||||
color: inherit; | |||||
background-color: #f0f4f7; | |||||
} | |||||
.padding { | |||||
padding: 15px; | |||||
} | |||||
.btn [class^="icon-"], | |||||
.nav [class^="icon-"], | |||||
.btn [class*=" icon-"], | |||||
.nav [class*=" icon-"] { | |||||
display: inline-block; | |||||
} | |||||
.dropdown-menu > li > a { | |||||
padding: 14px; | |||||
} | |||||
.dropdown-menu { | |||||
min-width: 200px; | |||||
padding: 0px; | |||||
font-size: 12px; | |||||
border-radius: 0px 0px 4px 4px; | |||||
} | |||||
.dropdown-menu .divider { | |||||
margin: 0px; | |||||
} | |||||
a.badge-hover:hover .badge, | |||||
a.badge-hover:focus .badge, | |||||
a.badge-hover:active .badge { | |||||
background-color: #D8DFE5; | |||||
} | |||||
.msgprint { | |||||
text-align: center; | |||||
} | |||||
.msgprint pre { | |||||
text-align: left; | |||||
} | |||||
.centered { | |||||
position: relative; | |||||
left: 50%; | |||||
transform: translate(-50%, 0); | |||||
-webkit-transform: translate(-50%, 0); | |||||
} | |||||
.border-top { | |||||
border-top: 1px solid #d1d8dd; | |||||
} | |||||
.border-bottom { | |||||
border-bottom: 1px solid #d1d8dd; | |||||
} | |||||
.border-left { | |||||
border-left: 1px solid #d1d8dd; | |||||
} | |||||
.border-right { | |||||
border-right: 1px solid #d1d8dd; | |||||
} | |||||
.border { | |||||
border: 1px solid #d1d8dd; | |||||
} | |||||
.close-inline { | |||||
font-size: 120%; | |||||
font-weight: bold; | |||||
line-height: 1; | |||||
cursor: pointer; | |||||
color: inherit; | |||||
display: inline-block; | |||||
} | |||||
.close-inline:hover, | |||||
.close-inline:focus { | |||||
text-decoration: none; | |||||
} | |||||
.nav-pills a, | .nav-pills a, | ||||
.nav-pills a:hover { | .nav-pills a:hover { | ||||
border-bottom: none; | border-bottom: none; | ||||
@@ -79,11 +163,6 @@ a.form-link { | |||||
.ui-autocomplete .link-option { | .ui-autocomplete .link-option { | ||||
font-weight: normal; | font-weight: normal; | ||||
} | } | ||||
.text-ellipsis { | |||||
white-space: nowrap; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
} | |||||
.scroll-to-top { | .scroll-to-top { | ||||
background-color: #fafbfc; | background-color: #fafbfc; | ||||
padding: 7px; | padding: 7px; | ||||
@@ -232,10 +311,6 @@ ul.linked-with-list li { | |||||
.form-group { | .form-group { | ||||
margin-bottom: 7px; | margin-bottom: 7px; | ||||
} | } | ||||
.bold, | |||||
.strong { | |||||
font-weight: bold; | |||||
} | |||||
.print-preview { | .print-preview { | ||||
padding: 0px; | padding: 0px; | ||||
max-width: 8.3in; | max-width: 8.3in; | ||||
@@ -305,10 +380,6 @@ ul.linked-with-list li { | |||||
#freeze.in { | #freeze.in { | ||||
opacity: 0.5; | opacity: 0.5; | ||||
} | } | ||||
kbd { | |||||
color: inherit; | |||||
background-color: #f0f4f7; | |||||
} | |||||
.msg-box { | .msg-box { | ||||
padding: 30px 15px; | padding: 30px 15px; | ||||
text-align: center; | text-align: center; | ||||
@@ -335,41 +406,9 @@ kbd { | |||||
margin-top: 5px; | margin-top: 5px; | ||||
text-align: center; | text-align: center; | ||||
} | } | ||||
.padding { | |||||
padding: 15px; | |||||
} | |||||
.set-filters .btn-xs { | .set-filters .btn-xs { | ||||
padding: 0px 10px 2px; | padding: 0px 10px 2px; | ||||
} | } | ||||
.btn [class^="icon-"], | |||||
.nav [class^="icon-"], | |||||
.btn [class*=" icon-"], | |||||
.nav [class*=" icon-"] { | |||||
display: inline-block; | |||||
} | |||||
.dropdown-menu > li > a { | |||||
padding: 14px; | |||||
} | |||||
.dropdown-menu { | |||||
min-width: 200px; | |||||
padding: 0px; | |||||
font-size: 12px; | |||||
border-radius: 0px 0px 4px 4px; | |||||
} | |||||
.dropdown-menu .divider { | |||||
margin: 0px; | |||||
} | |||||
a.badge-hover:hover .badge, | |||||
a.badge-hover:focus .badge, | |||||
a.badge-hover:active .badge { | |||||
background-color: #D8DFE5; | |||||
} | |||||
.msgprint { | |||||
text-align: center; | |||||
} | |||||
.msgprint pre { | |||||
text-align: left; | |||||
} | |||||
.intro-area, | .intro-area, | ||||
.footnote-area { | .footnote-area { | ||||
padding: 15px; | padding: 15px; | ||||
@@ -71,6 +71,7 @@ | |||||
.grid-row-open .form-in-grid { | .grid-row-open .form-in-grid { | ||||
opacity: 1; | opacity: 1; | ||||
height: auto; | height: auto; | ||||
overflow: visible; | |||||
} | } | ||||
.grid-form-heading { | .grid-form-heading { | ||||
padding: 10px 15px; | padding: 10px 15px; | ||||
@@ -1,12 +1,17 @@ | |||||
html, | |||||
html { | |||||
min-height: 100%; | |||||
} | |||||
body { | body { | ||||
height: 100%; | height: 100%; | ||||
/* The html and body elements cannot have any padding or margin. */ | /* The html and body elements cannot have any padding or margin. */ | ||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
margin: 0px; | margin: 0px; | ||||
padding: 0px !important; | padding: 0px !important; | ||||
} | } | ||||
html, | |||||
body { | |||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
} | |||||
.offcanvas-main-section-overlay { | .offcanvas-main-section-overlay { | ||||
display: none; | display: none; | ||||
cursor: pointer; | cursor: pointer; | ||||
@@ -1,12 +1,17 @@ | |||||
html, | |||||
html { | |||||
min-height: 100%; | |||||
} | |||||
body { | body { | ||||
height: 100%; | height: 100%; | ||||
/* The html and body elements cannot have any padding or margin. */ | /* The html and body elements cannot have any padding or margin. */ | ||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
margin: 0px; | margin: 0px; | ||||
padding: 0px !important; | padding: 0px !important; | ||||
} | } | ||||
html, | |||||
body { | |||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
} | |||||
.offcanvas-main-section-overlay { | .offcanvas-main-section-overlay { | ||||
display: none; | display: none; | ||||
cursor: pointer; | cursor: pointer; | ||||
@@ -1,12 +1,17 @@ | |||||
html, | |||||
html { | |||||
min-height: 100%; | |||||
} | |||||
body { | body { | ||||
height: 100%; | height: 100%; | ||||
/* The html and body elements cannot have any padding or margin. */ | /* The html and body elements cannot have any padding or margin. */ | ||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
margin: 0px; | margin: 0px; | ||||
padding: 0px !important; | padding: 0px !important; | ||||
} | } | ||||
html, | |||||
body { | |||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
} | |||||
.offcanvas-main-section-overlay { | .offcanvas-main-section-overlay { | ||||
display: none; | display: none; | ||||
cursor: pointer; | cursor: pointer; | ||||
@@ -1,12 +1,162 @@ | |||||
html, | |||||
a { | |||||
cursor: pointer; | |||||
} | |||||
a, | |||||
a:hover, | |||||
a:active, | |||||
a:focus { | |||||
outline: 0; | |||||
} | |||||
img { | |||||
max-width: 100%; | |||||
} | |||||
.text-color { | |||||
color: #36414c !important; | |||||
} | |||||
.text-muted { | |||||
color: #8d99a6 !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: #d1d8dd !important; | |||||
} | |||||
a, | |||||
.badge, | |||||
.ui-menu .ui-menu-item { | |||||
-webkit-transition: 0.2s; | |||||
-o-transition: 0.2s; | |||||
transition: 0.2s; | |||||
} | |||||
.btn { | |||||
-webkit-transition: background-color 0.2s; | |||||
-o-transition: background-color 0.2s; | |||||
transition: background-color 0.2s; | |||||
} | |||||
a.disabled, | |||||
a.disabled:hover { | |||||
color: #888; | |||||
cursor: default; | |||||
text-decoration: none; | |||||
} | |||||
a.grey, | |||||
.sidebar-section a, | |||||
.nav-pills a, | |||||
.control-value a, | |||||
.data-row a { | |||||
color: inherit; | |||||
border-bottom: 1px solid transparent; | |||||
margin-bottom: 0.4em; | |||||
} | |||||
a.grey:hover, | |||||
.sidebar-section a:hover, | |||||
.nav-pills a:hover, | |||||
.control-value a:hover, | |||||
.data-row a:hover { | |||||
border-bottom: 1px solid #212a33; | |||||
color: #212a33; | |||||
} | |||||
a.text-muted, | |||||
a.text-extra-muted { | |||||
border-bottom: 1px solid transparent; | |||||
} | |||||
a.text-muted:hover, | |||||
a.text-muted:focus, | |||||
a.text-extra-muted:hover, | |||||
a.text-extra-muted:focus { | |||||
color: inherit; | |||||
border-bottom: 1px solid #8d99a6; | |||||
} | |||||
.text-ellipsis { | |||||
white-space: nowrap; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
} | |||||
.bold, | |||||
.strong { | |||||
font-weight: bold; | |||||
} | |||||
kbd { | |||||
color: inherit; | |||||
background-color: #f0f4f7; | |||||
} | |||||
.padding { | |||||
padding: 15px; | |||||
} | |||||
.btn [class^="icon-"], | |||||
.nav [class^="icon-"], | |||||
.btn [class*=" icon-"], | |||||
.nav [class*=" icon-"] { | |||||
display: inline-block; | |||||
} | |||||
.dropdown-menu > li > a { | |||||
padding: 14px; | |||||
} | |||||
.dropdown-menu { | |||||
min-width: 200px; | |||||
padding: 0px; | |||||
font-size: 12px; | |||||
border-radius: 0px 0px 4px 4px; | |||||
} | |||||
.dropdown-menu .divider { | |||||
margin: 0px; | |||||
} | |||||
a.badge-hover:hover .badge, | |||||
a.badge-hover:focus .badge, | |||||
a.badge-hover:active .badge { | |||||
background-color: #D8DFE5; | |||||
} | |||||
.msgprint { | |||||
text-align: center; | |||||
} | |||||
.msgprint pre { | |||||
text-align: left; | |||||
} | |||||
.centered { | |||||
position: relative; | |||||
left: 50%; | |||||
transform: translate(-50%, 0); | |||||
-webkit-transform: translate(-50%, 0); | |||||
} | |||||
.border-top { | |||||
border-top: 1px solid #d1d8dd; | |||||
} | |||||
.border-bottom { | |||||
border-bottom: 1px solid #d1d8dd; | |||||
} | |||||
.border-left { | |||||
border-left: 1px solid #d1d8dd; | |||||
} | |||||
.border-right { | |||||
border-right: 1px solid #d1d8dd; | |||||
} | |||||
.border { | |||||
border: 1px solid #d1d8dd; | |||||
} | |||||
.close-inline { | |||||
font-size: 120%; | |||||
font-weight: bold; | |||||
line-height: 1; | |||||
cursor: pointer; | |||||
color: inherit; | |||||
display: inline-block; | |||||
} | |||||
.close-inline:hover, | |||||
.close-inline:focus { | |||||
text-decoration: none; | |||||
} | |||||
html { | |||||
min-height: 100%; | |||||
} | |||||
body { | body { | ||||
height: 100%; | height: 100%; | ||||
/* The html and body elements cannot have any padding or margin. */ | /* The html and body elements cannot have any padding or margin. */ | ||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
margin: 0px; | margin: 0px; | ||||
padding: 0px !important; | padding: 0px !important; | ||||
} | } | ||||
html, | |||||
body { | |||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
} | |||||
.offcanvas-main-section-overlay { | .offcanvas-main-section-overlay { | ||||
display: none; | display: none; | ||||
cursor: pointer; | cursor: pointer; | ||||
@@ -49,24 +199,85 @@ body { | |||||
.offcanvas .sidebar .dropdown-menu > li > a:active { | .offcanvas .sidebar .dropdown-menu > li > a:active { | ||||
background-color: #f0f4f7; | background-color: #f0f4f7; | ||||
} | } | ||||
html, | |||||
body { | |||||
height: 100%; | |||||
/* The html and body elements cannot have any padding or margin. */ | |||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
.avatar { | |||||
display: inline-block; | |||||
vertical-align: middle; | |||||
overflow: hidden; | |||||
width: 50px; | |||||
height: 50px; | |||||
} | } | ||||
a { | |||||
cursor: pointer; | |||||
.avatar img { | |||||
width: 100%; | |||||
height: auto; | |||||
border-radius: 4px; | |||||
} | } | ||||
a, | |||||
a:hover, | |||||
a:active, | |||||
a:focus { | |||||
outline: 0; | |||||
.avatar-empty { | |||||
border: 1px dashed #d1d8dd; | |||||
} | } | ||||
img { | |||||
max-width: 100%; | |||||
.avatar-small { | |||||
margin-right: 5px; | |||||
width: 24px; | |||||
height: 24px; | |||||
} | |||||
.avatar-medium { | |||||
margin-right: 5px; | |||||
width: 36px; | |||||
height: 36px; | |||||
} | |||||
.avatar-large { | |||||
margin-right: 10px; | |||||
width: 72px; | |||||
height: 72px; | |||||
} | |||||
.avatar-xs { | |||||
margin-right: 3px; | |||||
margin-top: -2px; | |||||
width: 17px; | |||||
height: 17px; | |||||
border: none; | |||||
border-radius: 3px; | |||||
} | |||||
.avatar-text { | |||||
display: inline; | |||||
width: 100%; | |||||
height: 0; | |||||
padding-bottom: 100%; | |||||
} | |||||
.indicator { | |||||
background: none; | |||||
font-size: 12px; | |||||
vertical-align: middle; | |||||
font-weight: bold; | |||||
color: #6c7680; | |||||
} | |||||
.indicator::before { | |||||
margin: 0 4px 0 0px; | |||||
content: ''; | |||||
display: inline-block; | |||||
height: 8px; | |||||
width: 8px; | |||||
border-radius: 8px; | |||||
} | |||||
.indicator.grey::before { | |||||
background: #f0f4f7; | |||||
} | |||||
.indicator.blue::before { | |||||
background: #5e64ff; | |||||
} | |||||
.indicator.red::before { | |||||
background: #ff5858; | |||||
} | |||||
.indicator.green::before { | |||||
background: #98d85b; | |||||
} | |||||
.indicator.orange::before { | |||||
background: #ffa00a; | |||||
} | |||||
.indicator.purple::before { | |||||
background: #743ee2; | |||||
} | |||||
.indicator.darkgrey::before { | |||||
background: #b8c2cc; | |||||
} | } | ||||
.content { | .content { | ||||
margin-bottom: 22px; | margin-bottom: 22px; | ||||
@@ -115,60 +326,6 @@ img { | |||||
padding: 20px 0px; | padding: 20px 0px; | ||||
min-height: 140px; | min-height: 140px; | ||||
} | } | ||||
.avatar { | |||||
display: inline-block; | |||||
vertical-align: middle; | |||||
overflow: hidden; | |||||
background-color: #f0f4f7; | |||||
border: 1px solid #d1d8dd; | |||||
background-size: cover; | |||||
background-position: center center; | |||||
background-repeat: no-repeat; | |||||
} | |||||
.avatar-small { | |||||
margin-right: 5px; | |||||
width: 30px; | |||||
height: 30px; | |||||
border-radius: 30px; | |||||
-moz-border-radius: 30px; | |||||
-webkit-border-radius: 30px; | |||||
} | |||||
.avatar-small img { | |||||
width: 30px; | |||||
} | |||||
.avatar-medium { | |||||
margin-right: 5px; | |||||
width: 48px; | |||||
height: 48px; | |||||
border-radius: 48px; | |||||
-moz-border-radius: 48px; | |||||
-webkit-border-radius: 48px; | |||||
} | |||||
.avatar-medium img { | |||||
width: 48px; | |||||
} | |||||
.avatar-large { | |||||
margin-right: 10px; | |||||
width: 72px; | |||||
height: 72px; | |||||
border-radius: 72px; | |||||
-moz-border-radius: 72px; | |||||
-webkit-border-radius: 72px; | |||||
} | |||||
.avatar-large img { | |||||
width: 72px; | |||||
} | |||||
.avatar-x-large { | |||||
margin-right: 10px; | |||||
width: 100px; | |||||
height: 100px; | |||||
border-radius: 100px; | |||||
-moz-border-radius: 100px; | |||||
-webkit-border-radius: 100px; | |||||
} | |||||
.avatar-x-large img { | |||||
width: 100px; | |||||
} | |||||
.carousel-control .icon { | .carousel-control .icon { | ||||
position: absolute; | position: absolute; | ||||
top: 50%; | top: 50%; | ||||
@@ -251,14 +408,8 @@ fieldset { | |||||
.page-container { | .page-container { | ||||
padding: 0px; | padding: 0px; | ||||
} | } | ||||
div[data-html-block="content"] { | |||||
padding-right: 15px; | |||||
} | |||||
.page-content hr { | |||||
margin-left: -15px; | |||||
margin-right: -30px; | |||||
} | |||||
.page-content { | .page-content { | ||||
padding-bottom: 20px; | |||||
border-right: 1px solid #d1d8dd; | border-right: 1px solid #d1d8dd; | ||||
} | } | ||||
.page-sidebar { | .page-sidebar { | ||||
@@ -363,38 +514,6 @@ a.active { | |||||
.docs-attr-desc { | .docs-attr-desc { | ||||
padding-left: 30px; | padding-left: 30px; | ||||
} | } | ||||
a.grey, | |||||
.nav-pills a, | |||||
.control-value a, | |||||
.data-row a { | |||||
color: inherit; | |||||
border-bottom: 1px solid transparent; | |||||
margin-bottom: 0.4em; | |||||
} | |||||
a.grey:hover, | |||||
.nav-pills a:hover, | |||||
.control-value a:hover, | |||||
.data-row a:hover { | |||||
border-bottom: 1px solid #212a33; | |||||
color: #212a33; | |||||
} | |||||
.text-muted { | |||||
color: #8d99a6 !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: #d1d8dd !important; | |||||
} | |||||
a.text-muted, | |||||
a.text-extra-muted { | |||||
border-bottom: 1px solid transparent; | |||||
} | |||||
a.text-muted:hover, | |||||
a.text-muted:focus, | |||||
a.text-extra-muted:hover, | |||||
a.text-extra-muted:focus { | |||||
color: inherit; | |||||
border-bottom: 1px solid #8d99a6; | |||||
} | |||||
.page-content { | .page-content { | ||||
min-height: 400px; | min-height: 400px; | ||||
} | } | ||||
@@ -51,7 +51,7 @@ frappe.ui.form.AssignTo = Class.extend({ | |||||
<a class="close" data-owner="%(owner)s">×</a>\ | <a class="close" data-owner="%(owner)s">×</a>\ | ||||
<div class="text-ellipsis" style="width: 80%">\ | <div class="text-ellipsis" style="width: 80%">\ | ||||
<div class="avatar avatar-small">\ | <div class="avatar avatar-small">\ | ||||
<img class="media-object" src="%(image)s">\ | |||||
<img class="media-object" src="%(image)s" alt="%(fullname)s">\ | |||||
</div>\ | </div>\ | ||||
<span>%(fullname)s</span>\ | <span>%(fullname)s</span>\ | ||||
</div>\ | </div>\ | ||||
@@ -104,7 +104,7 @@ frappe.form.formatters = { | |||||
var html = ""; | var html = ""; | ||||
$.each(JSON.parse(value || "[]"), function(i, v) { | $.each(JSON.parse(value || "[]"), function(i, v) { | ||||
if(v) html+= '<span class="avatar avatar-small" \ | if(v) html+= '<span class="avatar avatar-small" \ | ||||
style="margin-right: 3px;"><img src="'+frappe.user_info(v).image+'"></span>'; | |||||
style="margin-right: 3px;"><img src="'+frappe.user_info(v).image+'" alt="'+ frappe.user_info(v).abbr +'"></span>'; | |||||
}); | }); | ||||
return html; | return html; | ||||
}, | }, | ||||
@@ -22,8 +22,8 @@ frappe.ui.form.Share = Class.extend({ | |||||
var user_info = frappe.user_info(shared[i]) | var user_info = frappe.user_info(shared[i]) | ||||
$(repl('<span class="avatar avatar-small" title="' | $(repl('<span class="avatar avatar-small" title="' | ||||
+__("Shared with {0}", [user_info.fullname])+'">\ | +__("Shared with {0}", [user_info.fullname])+'">\ | ||||
<img class="media-object" src="%(image)s"></span>', | |||||
{image: user_info.image})).appendTo(this.parent); | |||||
<img class="media-object" src="%(image)s" alt="%(fullname)s"></span>', | |||||
{image: user_info.image, fullname: user_info.fullname})).appendTo(this.parent); | |||||
} | } | ||||
// share | // share | ||||
if(!me.frm.doc.__islocal) { | if(!me.frm.doc.__islocal) { | ||||
@@ -6,10 +6,35 @@ | |||||
frappe.user_info = function(uid) { | frappe.user_info = function(uid) { | ||||
if(!uid) | if(!uid) | ||||
uid = user; | uid = user; | ||||
if(!(frappe.boot.user_info && frappe.boot.user_info[uid])) { | if(!(frappe.boot.user_info && frappe.boot.user_info[uid])) { | ||||
return {fullname: toTitle(uid.split("@")[0]) || "Unknown"}; | |||||
var user_info = {fullname: toTitle(uid.split("@")[0]) || "Unknown"}; | |||||
} else { | |||||
var user_info = frappe.boot.user_info[uid]; | |||||
} | } | ||||
return frappe.boot.user_info[uid]; | |||||
user_info.abbr = get_abbr(user_info.fullname); | |||||
return user_info; | |||||
} | |||||
var get_abbr = function(txt, max_length) { | |||||
if (!txt) return ""; | |||||
var abbr = ""; | |||||
$.each(txt.split(" "), function(i, w) { | |||||
if (abbr.length >= (max_length || 2)) { | |||||
// break | |||||
return false; | |||||
} else if (!w.trim().length) { | |||||
// continue | |||||
return true; | |||||
} | |||||
abbr += w.trim()[0]; | |||||
}); | |||||
return abbr || "?"; | |||||
} | } | ||||
frappe.avatar = function(user, css_class, title) { | frappe.avatar = function(user, css_class, title) { | ||||
@@ -17,9 +42,10 @@ frappe.avatar = function(user, css_class, title) { | |||||
if(!title) title = frappe.user_info(user).fullname; | if(!title) title = frappe.user_info(user).fullname; | ||||
return repl('<span class="avatar %(css_class)s" title="%(title)s">\ | return repl('<span class="avatar %(css_class)s" title="%(title)s">\ | ||||
<img src="%(image)s"></span>', { | |||||
<img src="%(image)s" alt="%(abbr)s"></span>', { | |||||
image: image, | image: image, | ||||
title: title, | title: title, | ||||
abbr: frappe.user_info(user).abbr, | |||||
css_class: css_class || "avatar-small" | css_class: css_class || "avatar-small" | ||||
}); | }); | ||||
} | } | ||||
@@ -57,6 +83,9 @@ $.extend(frappe.user, { | |||||
image: function(uid) { | image: function(uid) { | ||||
return frappe.user_info(uid).image; | return frappe.user_info(uid).image; | ||||
}, | }, | ||||
abbr: function(uid) { | |||||
return frappe.user_info(uid).abbr; | |||||
}, | |||||
has_role: function(rl) { | has_role: function(rl) { | ||||
if(typeof rl=='string') | if(typeof rl=='string') | ||||
rl = [rl]; | rl = [rl]; | ||||
@@ -212,11 +212,12 @@ frappe.search.verbs = [ | |||||
try { | try { | ||||
var val = eval(txt); | var val = eval(txt); | ||||
var formatted_value = $.format('{0} = {1}', [txt, "<b>"+val+"</b>"]); | |||||
frappe.search.options.push({ | frappe.search.options.push({ | ||||
value: $.format('{0} = {1}', [txt, "<b>"+val+"</b>"]), | |||||
value: formatted_value, | |||||
match: val, | match: val, | ||||
onclick: function(match) { | onclick: function(match) { | ||||
msgprint(match, "Result"); | |||||
msgprint(formatted_value, "Result"); | |||||
} | } | ||||
}); | }); | ||||
} catch(e) { | } catch(e) { | ||||
@@ -20,7 +20,7 @@ | |||||
<li class="dropdown"> | <li class="dropdown"> | ||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" | <a class="dropdown-toggle" data-toggle="dropdown" href="#" | ||||
onclick="return false;"> | onclick="return false;"> | ||||
<img src="{%= frappe.user_info().image %}" class="navbar-user-image"> | |||||
<img src="{%= frappe.user_info().image %}" class="navbar-user-image" alt="{%= frappe.user.abbr() %}"> | |||||
<span class="toolbar-user-fullname">{%= frappe.user.full_name() %}</span> | <span class="toolbar-user-fullname">{%= frappe.user.full_name() %}</span> | ||||
<b class="caret"></b></a> | <b class="caret"></b></a> | ||||
<ul class="dropdown-menu" id="toolbar-user" role="menu"> | <ul class="dropdown-menu" id="toolbar-user" role="menu"> | ||||
@@ -36,7 +36,7 @@ | |||||
<div class="user-menu clearfix"> | <div class="user-menu clearfix"> | ||||
<div class="pull-left text-ellipsis" style="max-width: 75%;"> | <div class="pull-left text-ellipsis" style="max-width: 75%;"> | ||||
<a href="#Form/User/{%= encodeURIComponent(user) %}"> | <a href="#Form/User/{%= encodeURIComponent(user) %}"> | ||||
<img src="{%= frappe.user_info().image %}" class="navbar-user-image"> | |||||
<img src="{%= frappe.user_info().image %}" class="navbar-user-image" alt="{%= frappe.user.abbr() %}"> | |||||
<span>{%= frappe.user.full_name() %}</span> | <span>{%= frappe.user.full_name() %}</span> | ||||
</a> | </a> | ||||
</div> | </div> | ||||
@@ -0,0 +1,51 @@ | |||||
.avatar { | |||||
display: inline-block; | |||||
vertical-align: middle; | |||||
overflow: hidden; | |||||
width: 50px; | |||||
height: 50px; | |||||
} | |||||
.avatar img { | |||||
width: 100%; | |||||
height: auto; | |||||
border-radius: 4px; | |||||
} | |||||
.avatar-empty { | |||||
border: 1px dashed #d1d8dd; | |||||
} | |||||
.avatar-small { | |||||
margin-right: 5px; | |||||
width: 24px; | |||||
height: 24px; | |||||
} | |||||
.avatar-medium { | |||||
margin-right: 5px; | |||||
width: 36px; | |||||
height: 36px; | |||||
} | |||||
.avatar-large { | |||||
margin-right: 10px; | |||||
width: 72px; | |||||
height: 72px; | |||||
} | |||||
.avatar-xs { | |||||
margin-right: 3px; | |||||
margin-top: -2px; | |||||
width: 17px; | |||||
height: 17px; | |||||
border: none; | |||||
border-radius: 3px; | |||||
} | |||||
.avatar-text { | |||||
display: inline; | |||||
width: 100%; | |||||
height: 0; | |||||
padding-bottom: 100%; | |||||
} |
@@ -0,0 +1,156 @@ | |||||
@import "variables.less"; | |||||
@import "mixins.less"; | |||||
a { | |||||
cursor: pointer; | |||||
} | |||||
a, a:hover, a:active, a:focus { | |||||
outline: 0; | |||||
} | |||||
img { | |||||
max-width: 100%; | |||||
} | |||||
.text-color { | |||||
color: @text-color !important; | |||||
} | |||||
.text-muted { | |||||
color: @text-muted !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: @border-color !important; | |||||
} | |||||
// transition | |||||
a, | |||||
.badge, | |||||
.ui-menu .ui-menu-item { | |||||
.transition(.2s); | |||||
} | |||||
.btn { | |||||
.transition(background-color .2s); | |||||
} | |||||
a.disabled, a.disabled:hover { | |||||
color: #888; | |||||
cursor: default; | |||||
text-decoration: none; | |||||
} | |||||
a.grey, .sidebar-section a, .nav-pills a, .control-value a, .data-row a { | |||||
.underline; | |||||
} | |||||
a.grey:hover, .sidebar-section a:hover, .nav-pills a:hover, .control-value a:hover, .data-row a:hover { | |||||
.underline-hover; | |||||
} | |||||
a.text-muted, a.text-extra-muted { | |||||
border-bottom: 1px solid transparent; | |||||
} | |||||
a.text-muted:hover, | |||||
a.text-muted:focus, | |||||
a.text-extra-muted:hover, | |||||
a.text-extra-muted:focus { | |||||
color: inherit; | |||||
border-bottom: 1px solid @text-muted; | |||||
} | |||||
.text-ellipsis { | |||||
white-space: nowrap; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
} | |||||
.bold, | |||||
.strong { | |||||
font-weight: bold; | |||||
} | |||||
kbd { | |||||
color: inherit; | |||||
background-color: @btn-bg; | |||||
} | |||||
.padding { | |||||
padding: 15px; | |||||
} | |||||
.btn [class^="icon-"], .nav [class^="icon-"], .btn [class*=" icon-"], .nav [class*=" icon-"] { | |||||
display: inline-block; | |||||
} | |||||
// dropdowns | |||||
.dropdown-menu > li > a { | |||||
padding: 14px; | |||||
} | |||||
.dropdown-menu { | |||||
min-width: 200px; | |||||
padding: 0px; | |||||
font-size: @text-medium; | |||||
// only rounded bottoms | |||||
border-radius: 0px 0px 4px 4px; | |||||
} | |||||
.dropdown-menu .divider { | |||||
margin: 0px; | |||||
} | |||||
a.badge-hover& { | |||||
&:hover .badge, | |||||
&:focus .badge, | |||||
&:active .badge { | |||||
background-color: #D8DFE5; | |||||
} | |||||
} | |||||
.msgprint { | |||||
text-align: center; | |||||
pre { | |||||
text-align: left; | |||||
} | |||||
} | |||||
.centered { | |||||
position: relative; | |||||
left: 50%; | |||||
transform: translate(-50%, 0); | |||||
-webkit-transform: translate(-50%, 0); | |||||
} | |||||
.border-(@position) { | |||||
.border-@{position} { | |||||
border-@{position}: 1px solid @border-color; | |||||
} | |||||
} | |||||
.border-(top); | |||||
.border-(bottom); | |||||
.border-(left); | |||||
.border-(right); | |||||
.border { | |||||
border: 1px solid @border-color; | |||||
} | |||||
.close-inline { | |||||
font-size: 120%; | |||||
font-weight: bold; | |||||
line-height: 1; | |||||
cursor: pointer; | |||||
color: inherit; | |||||
display: inline-block; | |||||
} | |||||
.close-inline:hover, | |||||
.close-inline:focus { | |||||
text-decoration: none; | |||||
} |
@@ -1,59 +1,6 @@ | |||||
@import "variables.less"; | @import "variables.less"; | ||||
@import "mixins.less"; | @import "mixins.less"; | ||||
a, a:hover, a:active, a:focus { | |||||
outline: 0; | |||||
} | |||||
// transition | |||||
a, | |||||
.badge, | |||||
.ui-menu .ui-menu-item { | |||||
.transition(.2s); | |||||
} | |||||
.btn { | |||||
.transition(background-color .2s); | |||||
} | |||||
a.disabled, a.disabled:hover { | |||||
color: #888; | |||||
cursor: default; | |||||
text-decoration: none; | |||||
} | |||||
a.grey, .sidebar-section a, .nav-pills a, .control-value a, .data-row a { | |||||
.underline; | |||||
} | |||||
a.grey:hover, .sidebar-section a:hover, .nav-pills a:hover, .control-value a:hover, .data-row a:hover { | |||||
.underline-hover; | |||||
} | |||||
.text-color { | |||||
color: @text-color !important; | |||||
} | |||||
.text-muted { | |||||
color: @text-muted !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: @border-color !important; | |||||
} | |||||
a.text-muted, a.text-extra-muted { | |||||
border-bottom: 1px solid transparent; | |||||
} | |||||
a.text-muted:hover, | |||||
a.text-muted:focus, | |||||
a.text-extra-muted:hover, | |||||
a.text-extra-muted:focus { | |||||
color: inherit; | |||||
border-bottom: 1px solid @text-muted; | |||||
} | |||||
@import "common.less"; | |||||
.nav-pills a, .nav-pills a:hover { | .nav-pills a, .nav-pills a:hover { | ||||
border-bottom: none; | border-bottom: none; | ||||
@@ -78,12 +25,6 @@ a.form-link { | |||||
font-weight: normal; | font-weight: normal; | ||||
} | } | ||||
.text-ellipsis { | |||||
white-space: nowrap; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
} | |||||
.scroll-to-top { | .scroll-to-top { | ||||
background-color: @light-bg; | background-color: @light-bg; | ||||
padding: 7px; | padding: 7px; | ||||
@@ -264,12 +205,6 @@ ul.linked-with-list li { | |||||
margin-bottom: 7px; | margin-bottom: 7px; | ||||
} | } | ||||
.bold, | |||||
.strong { | |||||
font-weight: bold; | |||||
} | |||||
.print-preview { | .print-preview { | ||||
padding: 0px; | padding: 0px; | ||||
max-width: 8.3in; | max-width: 8.3in; | ||||
@@ -340,11 +275,6 @@ ul.linked-with-list li { | |||||
opacity: 0.5; | opacity: 0.5; | ||||
} | } | ||||
kbd { | |||||
color: inherit; | |||||
background-color: @btn-bg; | |||||
} | |||||
.msg-box { | .msg-box { | ||||
padding: 30px 15px; | padding: 30px 15px; | ||||
text-align: center; | text-align: center; | ||||
@@ -380,52 +310,10 @@ kbd { | |||||
text-align: center; | text-align: center; | ||||
} | } | ||||
.padding { | |||||
padding: 15px; | |||||
} | |||||
.set-filters .btn-xs { | .set-filters .btn-xs { | ||||
padding: 0px 10px 2px; | padding: 0px 10px 2px; | ||||
} | } | ||||
.btn [class^="icon-"], .nav [class^="icon-"], .btn [class*=" icon-"], .nav [class*=" icon-"] { | |||||
display: inline-block; | |||||
} | |||||
// dropdowns | |||||
.dropdown-menu > li > a { | |||||
padding: 14px; | |||||
} | |||||
.dropdown-menu { | |||||
min-width: 200px; | |||||
padding: 0px; | |||||
font-size: @text-medium; | |||||
// only rounded bottoms | |||||
border-radius: 0px 0px 4px 4px; | |||||
} | |||||
.dropdown-menu .divider { | |||||
margin: 0px; | |||||
} | |||||
a.badge-hover& { | |||||
&:hover .badge, | |||||
&:focus .badge, | |||||
&:active .badge { | |||||
background-color: #D8DFE5; | |||||
} | |||||
} | |||||
.msgprint { | |||||
text-align: center; | |||||
pre { | |||||
text-align: left; | |||||
} | |||||
} | |||||
.intro-area, | .intro-area, | ||||
.footnote-area { | .footnote-area { | ||||
padding: 15px; | padding: 15px; | ||||
@@ -83,6 +83,7 @@ | |||||
.grid-row-open .form-in-grid { | .grid-row-open .form-in-grid { | ||||
opacity: 1; | opacity: 1; | ||||
height: auto; | height: auto; | ||||
overflow: visible; | |||||
} | } | ||||
.grid-form-heading { | .grid-form-heading { | ||||
@@ -16,14 +16,6 @@ | |||||
font-weight: bold; | font-weight: bold; | ||||
} | } | ||||
// .navbar .breadcrumb-divider { | |||||
// margin-top: 10px; | |||||
// } | |||||
// .navbar .breadcrumb-divider i { | |||||
// color: #C0C9D2; | |||||
// } | |||||
.navbar-icon-home { | .navbar-icon-home { | ||||
vertical-align: middle; | vertical-align: middle; | ||||
} | } | ||||
@@ -1,13 +1,19 @@ | |||||
@import "variables.less"; | @import "variables.less"; | ||||
html, | |||||
html { | |||||
min-height: 100%; | |||||
} | |||||
body { | body { | ||||
height: 100%; | height: 100%; | ||||
/* The html and body elements cannot have any padding or margin. */ | /* The html and body elements cannot have any padding or margin. */ | ||||
overflow-x: hidden; /* Prevent scroll on narrow devices */ | |||||
margin: 0px; | margin: 0px; | ||||
padding: 0px !important; | padding: 0px !important; | ||||
} | |||||
html, | |||||
body { | |||||
overflow-x: hidden; /* Prevent scroll on narrow devices */ | |||||
} | } | ||||
.offcanvas-main-section-overlay { | .offcanvas-main-section-overlay { | ||||
@@ -1,24 +1,8 @@ | |||||
@import "variables.less"; | @import "variables.less"; | ||||
@import "common.less"; | |||||
@import "offcanvas.less"; | @import "offcanvas.less"; | ||||
html, | |||||
body { | |||||
height: 100%; | |||||
/* The html and body elements cannot have any padding or margin. */ | |||||
overflow-x: hidden; /* Prevent scroll on narrow devices */ | |||||
} | |||||
a { | |||||
cursor: pointer; | |||||
} | |||||
a, a:hover, a:active, a:focus { | |||||
outline: 0; | |||||
} | |||||
img { | |||||
max-width: 100%; | |||||
} | |||||
@import "avatar.less"; | |||||
@import "indicator.less"; | |||||
.content { | .content { | ||||
margin-bottom: 22px; | margin-bottom: 22px; | ||||
@@ -78,65 +62,6 @@ img { | |||||
min-height: 140px; | min-height: 140px; | ||||
} | } | ||||
.avatar { | |||||
display: inline-block; | |||||
vertical-align: middle; | |||||
overflow: hidden; | |||||
background-color: @btn-bg; | |||||
border: 1px solid @border-color; | |||||
background-size: cover; | |||||
background-position: center center; | |||||
background-repeat: no-repeat; | |||||
} | |||||
.avatar-small { | |||||
margin-right: 5px; | |||||
width: 30px; | |||||
height: 30px; | |||||
border-radius: 30px; | |||||
-moz-border-radius: 30px; | |||||
-webkit-border-radius: 30px; | |||||
} | |||||
.avatar-small img { | |||||
width: 30px; | |||||
} | |||||
.avatar-medium { | |||||
margin-right: 5px; | |||||
width: 48px; | |||||
height: 48px; | |||||
border-radius: 48px; | |||||
-moz-border-radius: 48px; | |||||
-webkit-border-radius: 48px; | |||||
} | |||||
.avatar-medium img { | |||||
width: 48px; | |||||
} | |||||
.avatar-large { | |||||
margin-right: 10px; | |||||
width: 72px; | |||||
height: 72px; | |||||
border-radius: 72px; | |||||
-moz-border-radius: 72px; | |||||
-webkit-border-radius: 72px; | |||||
} | |||||
.avatar-large img { | |||||
width: 72px; | |||||
} | |||||
.avatar-x-large { | |||||
margin-right: 10px; | |||||
width: 100px; | |||||
height: 100px; | |||||
border-radius: 100px; | |||||
-moz-border-radius: 100px; | |||||
-webkit-border-radius: 100px; | |||||
} | |||||
.avatar-x-large img { | |||||
width: 100px; | |||||
} | |||||
.carousel-control .icon { | .carousel-control .icon { | ||||
position: absolute; | position: absolute; | ||||
top: 50%; | top: 50%; | ||||
@@ -234,19 +159,7 @@ fieldset { | |||||
} | } | ||||
.page-content { | .page-content { | ||||
} | |||||
div[data-html-block="content"] { | |||||
padding-right: 15px; | |||||
} | |||||
.page-content hr { | |||||
margin-left: -15px; | |||||
margin-right: -30px; | |||||
} | |||||
.page-content { | |||||
padding-bottom: 20px; | |||||
border-right: 1px solid @border-color; | border-right: 1px solid @border-color; | ||||
} | } | ||||
@@ -290,17 +203,17 @@ div[data-html-block="content"] { | |||||
/* post and post list */ | /* post and post list */ | ||||
.web-list-item { | .web-list-item { | ||||
padding: 15px 0px; | |||||
padding: 15px 0px; | |||||
border-bottom: 1px solid @border-color; | border-bottom: 1px solid @border-color; | ||||
margin-right: -30px; | margin-right: -30px; | ||||
padding-right: 30px; | padding-right: 30px; | ||||
h3 { | h3 { | ||||
margin: 0 0 5px 0; | |||||
margin: 0 0 5px 0; | |||||
a { | a { | ||||
color: inherit !important; | |||||
text-decoration: none; | |||||
color: inherit !important; | |||||
text-decoration: none; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -380,39 +293,6 @@ a.active { | |||||
} | } | ||||
// links and text | |||||
a.grey, .nav-pills a, .control-value a, .data-row a { | |||||
color: inherit; | |||||
border-bottom: 1px solid transparent; | |||||
margin-bottom: 0.4em; | |||||
} | |||||
a.grey:hover, .nav-pills a:hover, .control-value a:hover, .data-row a:hover { | |||||
border-bottom: 1px solid @grey-link-color; | |||||
color: @grey-link-color; | |||||
} | |||||
.text-muted { | |||||
color: @text-muted !important; | |||||
} | |||||
.text-extra-muted { | |||||
color: @border-color !important; | |||||
} | |||||
a.text-muted, a.text-extra-muted { | |||||
border-bottom: 1px solid transparent; | |||||
} | |||||
a.text-muted:hover, | |||||
a.text-muted:focus, | |||||
a.text-extra-muted:hover, | |||||
a.text-extra-muted:focus { | |||||
color: inherit; | |||||
border-bottom: 1px solid @text-muted; | |||||
} | |||||
.page-content { | .page-content { | ||||
min-height: 400px; | min-height: 400px; | ||||
} | } | ||||
@@ -50,9 +50,9 @@ Built on Frappe.io. Free and Open Source Framework for the Web. https://frappe.i | |||||
{%- endif %} | {%- endif %} | ||||
{%- endblock -%} | {%- endblock -%} | ||||
{%- block navbar -%}{% include "templates/includes/navbar.html" %}{%- endblock -%} | |||||
{%- block navbar -%}{% include "templates/includes/navbar/navbar.html" %}{%- endblock -%} | |||||
<div class="container"> | <div class="container"> | ||||
<div class="page-container" id="page-{{ name or page_name }}"> | |||||
<div class="page-container" id="page-{{ name or page_name }}" data-path="{{ pathname }}"> | |||||
<div class="row"> | <div class="row"> | ||||
<div class="col-sm-10 col-xs-12 page-content"> | <div class="col-sm-10 col-xs-12 page-content"> | ||||
<div data-html-block="header"> | <div data-html-block="header"> | ||||
@@ -61,7 +61,7 @@ Built on Frappe.io. Free and Open Source Framework for the Web. https://frappe.i | |||||
<div class="page-breadcrumbs" data-html-block="breadcrumbs"> | <div class="page-breadcrumbs" data-html-block="breadcrumbs"> | ||||
{%- if breadcrumbs is defined -%}{{ breadcrumbs }}{%- endif -%} | {%- if breadcrumbs is defined -%}{{ breadcrumbs }}{%- endif -%} | ||||
</div> | </div> | ||||
<div class="" data-html-block="content"> | |||||
<div class="page-content-block" data-html-block="content"> | |||||
{%- block content -%}{{ content or "" }}{%- endblock -%} | {%- block content -%}{{ content or "" }}{%- endblock -%} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -82,14 +82,14 @@ Built on Frappe.io. Free and Open Source Framework for the Web. https://frappe.i | |||||
</footer> | </footer> | ||||
</div> | </div> | ||||
<div> | <div> | ||||
{%- block footer -%}{% include "templates/includes/footer.html" %}{%- endblock -%} | |||||
{%- block footer -%}{% include "templates/includes/footer/footer.html" %}{%- endblock -%} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="modal-backdrop offcanvas-main-section-overlay"></div> | <div class="modal-backdrop offcanvas-main-section-overlay"></div> | ||||
<div class="sidebar sidebar-right visible-xs"> | <div class="sidebar sidebar-right visible-xs"> | ||||
{% block offcanvas_sidebar -%} | {% block offcanvas_sidebar -%} | ||||
<div class="sidebar-navbar-items"> | <div class="sidebar-navbar-items"> | ||||
{% include "frappe/templates/includes/navbar_items.html" %} | |||||
{% include "templates/includes/navbar/navbar_items.html" %} | |||||
</div> | </div> | ||||
<div class="sidebar-page-sidebar" data-html-block="sidebar"> | <div class="sidebar-page-sidebar" data-html-block="sidebar"> | ||||
{%- if sidebar is defined -%} | {%- if sidebar is defined -%} | ||||
@@ -19,11 +19,11 @@ | |||||
</article> | </article> | ||||
{% if blogger_info %} | {% if blogger_info %} | ||||
<hr /> | <hr /> | ||||
{% include "templates/includes/blogger.html" %} | |||||
{% include "templates/includes/blog/blogger.html" %} | |||||
{% endif %} | {% endif %} | ||||
<hr> | <hr> | ||||
<h3>Comments</h3> | <h3>Comments</h3> | ||||
{% include 'templates/includes/comments.html' %} | |||||
{% include 'templates/includes/comments/comments.html' %} | |||||
<script> | <script> | ||||
$(function() { | $(function() { | ||||
if(window.logged_in && getCookie("system_user")==="yes") { | if(window.logged_in && getCookie("system_user")==="yes") { | ||||
@@ -36,4 +36,4 @@ $(function() { | |||||
</script> | </script> | ||||
{% endblock %} | {% endblock %} | ||||
{% block footer %}{% include 'templates/includes/blog_footer.html' %}{% endblock %} | |||||
{% block footer %}{% include 'templates/includes/blog/blog_footer.html' %}{% endblock %} |
@@ -161,7 +161,7 @@ | |||||
<div class="col-sm-offset-3 col-sm-9"> | <div class="col-sm-offset-3 col-sm-9"> | ||||
<hr> | <hr> | ||||
<h3>{{ _("Comments") }}</h3> | <h3>{{ _("Comments") }}</h3> | ||||
{% include 'templates/includes/comments.html' %} | |||||
{% include 'templates/includes/comments/comments.html' %} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
{%- endif %} | {%- endif %} | ||||
@@ -9,7 +9,7 @@ | |||||
{% if enable_comments -%} | {% if enable_comments -%} | ||||
<hr> | <hr> | ||||
<h3>Discuss</h3> | <h3>Discuss</h3> | ||||
{% include 'templates/includes/comments.html' %} | |||||
{% include 'templates/includes/comments/comments.html' %} | |||||
{%- endif %} | {%- endif %} | ||||
</div> | </div> | ||||
<script> | <script> | ||||
@@ -1,60 +0,0 @@ | |||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
// MIT License. See license.txt | |||||
// js inside blog page | |||||
frappe.blog = { | |||||
start: 0, | |||||
get_list: function() { | |||||
$.ajax({ | |||||
method: "GET", | |||||
url: "/api/method/frappe.templates.pages.blog.get_blog_list", | |||||
data: { | |||||
start: frappe.blog.start, | |||||
by: get_url_arg("by"), | |||||
category: window.category || get_url_arg("category") | |||||
}, | |||||
dataType: "json", | |||||
success: function(data) { | |||||
if(data.exc) { | |||||
console.log(data.exc); | |||||
} | |||||
if(data.message) { | |||||
$(data.message).appendTo($("#blog-list")); | |||||
frappe.blog.set_paging(); | |||||
} | |||||
} | |||||
}); | |||||
}, | |||||
set_paging: function(result_length) { | |||||
frappe.blog.start = $(".blog-post-preview").length; | |||||
if(!frappe.blog.start || (frappe.blog.start % 20) != 0) { | |||||
if(frappe.blog.start) { | |||||
$("#next-page").toggle(false); | |||||
$(".blog-message").html(__("Nothing more to show.")); | |||||
} else { | |||||
$("#next-page").toggle(false); | |||||
$(".blog-message").html(__("No posts written yet.")); | |||||
} | |||||
} else { | |||||
$("#next-page").toggle(true); | |||||
} | |||||
} | |||||
}; | |||||
frappe.ready(function() { | |||||
frappe.blog.set_paging(); | |||||
$("#next-page").click(function() { | |||||
frappe.blog.get_list(); | |||||
}) | |||||
if(get_url_arg("by_name")) { | |||||
$("#blot-subtitle").html("Posts by " + get_url_arg("by_name")).toggle(true); | |||||
} | |||||
if(get_url_arg("category")) { | |||||
$("#blot-subtitle").html("Posts filed under " + get_url_arg("category")).toggle(true); | |||||
} | |||||
}); |
@@ -7,11 +7,11 @@ window.category = null; | |||||
{% block content %} | {% block content %} | ||||
<div class="blog-list-content"> | <div class="blog-list-content"> | ||||
{% if blog_introduction %} | {% if blog_introduction %} | ||||
<p>{{ blog_introduction }}</p> | |||||
<p class="blog-introduction">{{ blog_introduction }}</p> | |||||
{% endif %} | {% endif %} | ||||
<h3 id="blot-subtitle" style="display:none;"></h3> | |||||
<h3 id="blot-subtitle" class="hide"></h3> | |||||
<div id="blog-list"> | <div id="blog-list"> | ||||
{{ posts }} | |||||
{% include "templates/includes/list/list.html" %} | |||||
</div> | </div> | ||||
<div class="blog-footer"> | <div class="blog-footer"> | ||||
<p class="blog-message text-muted"></p> | <p class="blog-message text-muted"></p> | ||||
@@ -21,9 +21,6 @@ window.category = null; | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<script> | |||||
{% include "templates/includes/blog.js" %} | |||||
</script> | |||||
{% endblock %} | {% endblock %} | ||||
{% block footer %}{% include 'templates/includes/blog_footer.html' %}{% endblock %} | |||||
{% block footer %}{% include 'templates/includes/blog/blog_footer.html' %}{% endblock %} |
@@ -0,0 +1,14 @@ | |||||
{%- set post = doc -%} | |||||
<div class="row web-list-item"> | |||||
<div class="col-xs-2 text-center text-muted"> | |||||
<h1 class="blog-day" style="margin: 0px;">{{ post.day }}</h1> | |||||
<div class="small">{{ post.month }} {{ post.year }}</div> | |||||
</div> | |||||
<div class="col-xs-10"> | |||||
<h3><a href="/{{ post.page_name }}">{{ post.title }}</a></h3> | |||||
<p class="text-muted">{{ post.content }}</p> | |||||
<p class="text-muted small"> | |||||
<a href="/blog?by={{ post.blogger }}&by_name={{ post.full_name }}"> | |||||
{{ post.full_name }}</a> / {{ post.comment_text }}</p> | |||||
</div> | |||||
</div> |
@@ -1,16 +0,0 @@ | |||||
{% for post in posts %} | |||||
<div class="row web-list-item"> | |||||
<div class="col-xs-2 text-center text-muted"> | |||||
<h1 class="blog-day" style="margin: 0px;">{{ post.day }}</h1> | |||||
<div class="small">{{ post.month }} {{ post.year }}</div> | |||||
</div> | |||||
<div class="col-xs-10"> | |||||
<h3><a href="/{{ post.page_name }}">{{ post.title }}</a></h3> | |||||
<p class="text-muted">{{ post.content }}</p> | |||||
<p class="text-muted small"> | |||||
<a href="/blog?by={{ post.blogger }}&by_name={{ post.full_name }}"> | |||||
{{ post.full_name }}</a> / {{ post.comment_text }}</p> | |||||
</div> | |||||
</div> | |||||
{% endfor %} | |||||
<!-- nothing --> |
@@ -1,8 +1,12 @@ | |||||
{% if parents and parents|length > 0 %} | {% if parents and parents|length > 0 %} | ||||
<ul class="breadcrumb"> | <ul class="breadcrumb"> | ||||
{% for parent in parents %} | |||||
<li><a href="{{ parents[-1].name }}"><span class="icon icon-angle-left"></span> | |||||
{{ parents[-1].page_title or parents[-1].title or "" }}</a></li> | |||||
{# | |||||
<!-- {% for parent in parents %} | |||||
<li><a href="{{ parent.name }}">{{ parent.page_title or parent.title or "" }}</a></li> | <li><a href="{{ parent.name }}">{{ parent.page_title or parent.title or "" }}</a></li> | ||||
{% endfor %} | {% endfor %} | ||||
<li class="active">{{ title or "" }}</li> | |||||
<li class="active">{{ title or "" }}</li> --> | |||||
#} | |||||
</ul> | </ul> | ||||
{% endif %} | {% endif %} |
@@ -6,7 +6,7 @@ | |||||
<div itemscope itemtype="http://schema.org/UserComments" id="comment-list"> | <div itemscope itemtype="http://schema.org/UserComments" id="comment-list"> | ||||
{% for comment in comment_list %} | {% for comment in comment_list %} | ||||
{% include "templates/includes/comment.html" %} | |||||
{% include "templates/includes/comments/comment.html" %} | |||||
{% endfor %} | {% endfor %} | ||||
</div> | </div> | ||||
@@ -75,7 +75,7 @@ frappe.ready(function() { | |||||
frappe.call({ | frappe.call({ | ||||
btn: this, | btn: this, | ||||
type: "POST", | type: "POST", | ||||
method: "frappe.templates.includes.comments.add_comment", | |||||
method: "frappe.templates.includes.comments.comments.add_comment", | |||||
args: args, | args: args, | ||||
callback: function(r) { | callback: function(r) { | ||||
if(r.exc) { | if(r.exc) { |
@@ -42,7 +42,7 @@ | |||||
{# powered #} | {# powered #} | ||||
<p class="text-right footer-powered"> | <p class="text-right footer-powered"> | ||||
{% block powered %} | {% block powered %} | ||||
{% include "templates/includes/footer_powered.html" %} | |||||
{% include "templates/includes/footer/footer_powered.html" %} | |||||
{% endblock %} | {% endblock %} | ||||
</p> | </p> | ||||
</div> | </div> | ||||
@@ -50,6 +50,6 @@ | |||||
</div> | </div> | ||||
</section> | </section> | ||||
<section> | <section> | ||||
{% block extension %}{% include "templates/includes/footer_extension.html" %}{% endblock %} | |||||
{% block extension %}{% include "templates/includes/footer/footer_extension.html" %}{% endblock %} | |||||
</section> | </section> | ||||
</footer> | </footer> |
@@ -1,57 +0,0 @@ | |||||
{% set post_url = frappe.local.request.path + "?view=post&name=" + post.name %} | |||||
{% set edit_url = frappe.local.request.path + "?view=edit&name=" + post.name %} | |||||
<div class="media post {% if post.parent_post -%} child-post {%- endif %}" | |||||
data-name="{{ post.name }}" | |||||
data-group="{{ post.website_group }}" | |||||
itemscope itemtype="http://schema.org/Article"> | |||||
<a class="pull-left media-link" {% if view.name!="post" %} href="{{ post_url }}" {% endif %}> | |||||
<img class="media-object post-avatar" src="{{ post.user_image }}"> | |||||
</a> | |||||
<div class="media-body"> | |||||
{%- if not post.parent_post -%} | |||||
<h4 class="media-heading" itemprop="headline"> | |||||
{%- if view.name != "post" -%} | |||||
<a class="no-decoration" | |||||
href="{{ post_url }}">{{ post.title }}</a> | |||||
{%- else -%} | |||||
{{ post.title }} | |||||
{%- endif -%} | |||||
</h4> | |||||
{%- endif -%} | |||||
<ul class="list-inline small text-muted post-options"> | |||||
{% if view and view.upvote and not post.parent_post %}<li class="upvote"> | |||||
<a><span class="upvote-count {% if not post.upvotes %}hide{% endif %}">{{ post.upvotes }}</span> | |||||
<i class="icon-thumbs-up"></i></a></li>{% endif %} | |||||
{%- if not post.parent_post and view.name != "post" -%} | |||||
<li><a itemprop="url" href="{{ post_url }}"> | |||||
{% if not post.post_reply_count -%} | |||||
<i class="icon-reply"></i> Reply | |||||
{% elif post.post_reply_count == 1 %} | |||||
{{ post.post_reply_count }} Reply | |||||
{% else %} | |||||
{{ post.post_reply_count }} Replies | |||||
{%- endif %} | |||||
</a></li> | |||||
{%- endif -%} | |||||
<li><span class="frappe-timestamp" data-timestamp="{{ post.creation }}"></span></li> | |||||
<li>by <span itemprop="author">{{ post.first_name or "" }} {{ post.last_name or "" }}</span></li> | |||||
<li class="edit-post pull-right hide" data-owner="{{ post.owner }}"> | |||||
<a class="text-muted" href="{{ edit_url }}">[edit]</a> | |||||
</li> | |||||
</ul> | |||||
<div itemprop="articleBody" class="post-content"> | |||||
{%- if post.is_task==1 and post.assigned_to -%} | |||||
<span class="label label-info assigned-label"> | |||||
<i class="icon-pencil"></i> {{ post.assigned_to_fullname }}</span> | |||||
{%- elif post.is_event==1 and post.event_datetime -%} | |||||
<span class="label label-info event-label"><i class="icon-calendar"></i> | |||||
<span class="event-timestamp" data-timestamp="{{ post.event_datetime }}"></span></span> | |||||
{%- endif -%} | |||||
{{ post.content|markdown }} | |||||
{%- if post.picture_url -%} | |||||
<img src="{{ post.picture_url }}" class="img-responsive post-picture" /> | |||||
{%- endif -%} | |||||
</div> | |||||
</div> | |||||
</div> |
@@ -0,0 +1,22 @@ | |||||
<div class="website-list-filters"> | |||||
<div class="row"> | |||||
<div class="col-xs-6"> | |||||
<form class="form-inline form-search" action="/{{ pathname }}"> | |||||
<div class="input-group"> | |||||
<input class="form-control" doctype="text" name="txt" | |||||
placeholder="Search..." value="{{ txt or '' }}"> | |||||
<span class="input-group-btn"> | |||||
<button class="btn btn-default" type="submit"> | |||||
<i class="icon-search"></i></button> | |||||
</span> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
{% if txt %} | |||||
<div> | |||||
<div class="filter-message small text-muted">Results filtered by <b>{{ txt }}</b>. | |||||
<a href="/{{ pathname }}" class="text-muted">( <span class="close-inline">×</span> {{ _("clear") }} )</a></div> | |||||
</div> | |||||
{% endif %} | |||||
</div> |
@@ -0,0 +1,31 @@ | |||||
.website-list .result { | |||||
border: 1px solid {{ border_color or "#d1d8dd" }}; | |||||
} | |||||
.website-list-row { | |||||
display: block; | |||||
border-bottom: 1px solid {{ border_color or "#d1d8dd" }}; | |||||
padding: 15px; | |||||
} | |||||
.website-list-row:last-child { | |||||
border-bottom: none; | |||||
} | |||||
.website-list-filters { | |||||
padding: 15px; | |||||
border: 1px solid {{ border_color or "#d1d8dd" }}; | |||||
border-bottom: none; | |||||
} | |||||
.website-list-filters .form-search .input-group { | |||||
width: 100%; | |||||
} | |||||
.website-list-filters .filter-message { | |||||
padding-top: 7px; | |||||
} | |||||
.website-list-filters .clear-filters { | |||||
margin-left: 15px; | |||||
} |
@@ -0,0 +1,19 @@ | |||||
<div class="website-list" data-doctype="{{ doctype }}" data-txt="{{ txt or '[notxt]' }}"> | |||||
{% if not hide_filters -%} | |||||
{% include "templates/includes/list/filters.html" %} | |||||
{%- endif %} | |||||
<div class="result"> | |||||
{% for item in result %} | |||||
{{ item }} | |||||
{% endfor %} | |||||
{% if not result -%} | |||||
<div class="text-muted padding"> | |||||
{{ no_result_message or _("Nothing to show") }} | |||||
</div> | |||||
{%- endif %} | |||||
</div> | |||||
<div class="more-block text-center {% if not show_more -%} hide {%- endif %}"> | |||||
<button class="btn btn-default btn-more">More</button> | |||||
</div> | |||||
</div> |
@@ -0,0 +1,31 @@ | |||||
frappe.ready(function() { | |||||
var next_start = {{ next_start }}; | |||||
var result_wrapper = $(".website-list .result"); | |||||
$(".website-list .btn-more").on("click", function() { | |||||
return $.ajax({ | |||||
url:"/api/method/frappe.templates.pages.list.get", | |||||
data: { | |||||
doctype: "{{ doctype }}", | |||||
txt: "{{ txt or '' }}", | |||||
limit_start: next_start | |||||
}, | |||||
statusCode: { | |||||
200: function(data) { | |||||
var data = data.message; | |||||
next_start = data.next_start; | |||||
$.each(data.result, function(i, d) { | |||||
$(d).appendTo(result_wrapper); | |||||
}); | |||||
toggle_more(data.show_more); | |||||
} | |||||
} | |||||
}); | |||||
}); | |||||
var toggle_more = function(show) { | |||||
if (!show) { | |||||
$(".website-list .more-block").addClass("hide"); | |||||
} | |||||
}; | |||||
}) |
@@ -0,0 +1,21 @@ | |||||
{% set doc = frappe.get_doc(doc) %} | |||||
{% set subject = doc.get(meta.title_field or "name") %} | |||||
<a class="website-list-row" href="/{{ pathname or doc.doctype }}/{{ doc.name }}" no-pjax> | |||||
<div class="row"> | |||||
<div class="{% if subject == doc.name -%} col-sm-10 {%- else %} col-sm-6 {%- endif %} col-xs-7"> | |||||
<div class="row"> | |||||
<div class="col-sm-9">{{ subject }}</div> | |||||
<div class="col-sm-3"> | |||||
{{ doc.status or "" }} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{% if subject != doc.name %} | |||||
<div class="col-sm-2 text-muted text-right"> | |||||
{{ doc.name }} | |||||
</div> | |||||
{% endif %} | |||||
<div class="col-sm-2 small text-muted text-right" title="{{ frappe.utils.format_datetime(doc.creation, "medium") }}"> | |||||
{{ frappe.utils.pretty_date(doc.creation) }}</div> | |||||
</div> | |||||
</a> |
@@ -11,7 +11,7 @@ | |||||
</div> | </div> | ||||
<div class="hidden-xs"> | <div class="hidden-xs"> | ||||
{% block navbar_items %} | {% block navbar_items %} | ||||
{% include "frappe/templates/includes/navbar_items.html" %} | |||||
{% include "templates/includes/navbar/navbar_items.html" %} | |||||
{% endblock %} | {% endblock %} | ||||
</div> | </div> | ||||
</div> | </div> |
@@ -2,7 +2,7 @@ | |||||
<ul class="nav navbar-nav navbar-left"> | <ul class="nav navbar-nav navbar-left"> | ||||
{%- for page in top_bar_items -%} | {%- for page in top_bar_items -%} | ||||
{% if not page.parent_label and not page.right -%} | {% if not page.parent_label and not page.right -%} | ||||
{% include "templates/includes/navbar_link.html" %} | |||||
{% include "templates/includes/navbar/navbar_link.html" %} | |||||
{%- endif -%} | {%- endif -%} | ||||
{%- endfor %} | {%- endfor %} | ||||
</ul> | </ul> | ||||
@@ -10,16 +10,15 @@ | |||||
<ul class="nav navbar-nav navbar-right"> | <ul class="nav navbar-nav navbar-right"> | ||||
{%- for page in top_bar_items -%} | {%- for page in top_bar_items -%} | ||||
{% if not page.parent_label and page.right -%} | {% if not page.parent_label and page.right -%} | ||||
{% include "templates/includes/navbar_link.html" %} | |||||
{% include "templates/includes/navbar/navbar_link.html" %} | |||||
{%- endif -%} | {%- endif -%} | ||||
{%- endfor %} | {%- endfor %} | ||||
<!-- post login tools --> | <!-- post login tools --> | ||||
<li class="dropdown logged-in" id="website-post-login" | <li class="dropdown logged-in" id="website-post-login" | ||||
data-label="website-post-login" style="display: none"> | data-label="website-post-login" style="display: none"> | ||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"> | <a href="#" class="dropdown-toggle" data-toggle="dropdown"> | ||||
<img class="user-picture" | |||||
style="min-width: 20px; max-height: 20px; border-radius: 4px"/> | |||||
<b class="full-name"></b><b class="caret"></b> | |||||
<span class="avatar avatar-small user-image-wrapper"><img class="user-image"/></span> | |||||
<span class="visible-xs full-name"></span> | |||||
</a> | </a> | ||||
<ul class="dropdown-menu" role="menu"> | <ul class="dropdown-menu" role="menu"> | ||||
{%- for child in post_login -%} | {%- for child in post_login -%} | ||||
@@ -29,9 +28,6 @@ | |||||
{%- if child.url -%} | {%- if child.url -%} | ||||
<a href="{{ child.url }}" {{ child.target or '' }} | <a href="{{ child.url }}" {{ child.target or '' }} | ||||
rel="nofollow"> | rel="nofollow"> | ||||
{%- if child.icon -%} | |||||
<i class="icon-fixed-width {{ child.icon }}"></i> | |||||
{%- endif -%} | |||||
{{ child.label }} | {{ child.label }} | ||||
</a> | </a> | ||||
{%- endif -%} | {%- endif -%} | ||||
@@ -40,5 +36,5 @@ | |||||
</ul> | </ul> | ||||
</li> | </li> | ||||
<li class="btn-login-area"><a href="/login"> | <li class="btn-login-area"><a href="/login"> | ||||
{%- if not disable_signup %}Sign Up / {% endif -%} Login</a></li> | |||||
{%- if not disable_signup %}{{ _("Sign Up") }} / {% endif -%} {{ _("Login") }}</a></li> | |||||
</ul> | </ul> |
@@ -1,66 +0,0 @@ | |||||
{% set parent_post = post.parent_post if post else parent_post %} | |||||
<div class="post-editor well" | |||||
{% if parent_post %}data-parent-post="{{ parent_post }}"{% endif %} | |||||
{% if post %}data-post="{{ post.name }}"{% endif %}> | |||||
{%- if not (post and post.parent_post) and not parent_post-%} | |||||
<input type="text" class="form-group form-control h3" placeholder="Title" | |||||
data-fieldname="title" {%- if post and post.title -%}value="{{ post.title }}"{%- endif -%}> | |||||
{%- endif -%} | |||||
<textarea class="form-group form-control post-add-textarea" placeholder="Enter text" | |||||
data-fieldname="content">{%- if post and post.content -%}{{ post.content }}{%- endif -%}</textarea> | |||||
<!-- task and events related fields --> | |||||
{%- if view.name != "post" and not (post and post.parent_post) -%} | |||||
{%- if group.group_type == "Tasks" -%} | |||||
<input type="text" class="form-group form-control control-assign" | |||||
placeholder="Assign this task to someone" | |||||
{%- if post and post.assigned_to_fullname -%}value="{{ post.assigned_to_fullname }}"{%- endif -%} /> | |||||
<input type="hidden" class="form-group form-control hide" data-fieldname="assigned_to" | |||||
{% if post and post.assigned_to %}value="{{ post.assigned_to }}"{% endif %}/> | |||||
<div class="assigned-to alert alert-success {% if not (post and post.assigned_to) %}hide{% endif %}" | |||||
style="margin: 10px 0px;"> | |||||
<div class="row"> | |||||
<div class="col-xs-10"> | |||||
<div class="assigned-user user-user"> | |||||
{%- if post and user -%} | |||||
{% include "templates/includes/user_display.html" %} | |||||
{%- endif -%} | |||||
</div> | |||||
</div> | |||||
<div class="col-xs-2"> | |||||
<a class="close">×</a> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="form-group task-status {% if not post %}hide{% endif %}"> | |||||
<label>Status</label> | |||||
<select class="form-control" data-fieldname="status"> | |||||
{% for opt in ("Open", "Closed") %} | |||||
<option value="{{ opt }}" {% if post and opt==post.status %}selected{% endif %}>{{ opt }}</option> | |||||
{% endfor %} | |||||
</select> | |||||
</div> | |||||
{%- elif group.group_type == "Events" -%} | |||||
<input type="text" class="form-group form-control control-event" | |||||
placeholder="Enter Event Date and Time" /> | |||||
<input type="hidden" class="form-group form-control hide" data-fieldname="event_datetime" | |||||
{% if post and post.event_datetime %}value="{{ post.event_datetime }}"{% endif %}/> | |||||
{%- endif -%} | |||||
{%- endif -%} | |||||
<div class="text-muted small">tab + enter to post / <a target="_blank" class="text-muted" | |||||
href="/markdown-cheatsheet" tabindex="-1">markdown formatting</a></div> | |||||
<div class="post-picture hide" style="margin: 10px 0px;"> | |||||
<img src="{{ post.picture_url if post else ''}}" class="img-responsive" /> | |||||
</div> | |||||
<div class="clearfix"> | |||||
<button class="btn btn-default btn-post-add pull-right"><i class="icon-plus"></i> Add Post</button> | |||||
<button class="btn btn-default btn-post-save pull-right hide"><i class="icon-ok"></i> Save Post</button> | |||||
<button class="btn btn-default btn-post-add-picture pull-right"> | |||||
<i class="icon-camera"></i> Add Picture | |||||
</button> | |||||
<!-- hidden file input --> | |||||
<input type="file" class="control-post-add-picture hide" | |||||
style="position: absolute; top: 0; width: 0; height: 0;"> | |||||
</div> | |||||
</div> |
@@ -1,11 +0,0 @@ | |||||
{% if posts %} | |||||
{% for post in posts %} | |||||
{% include "templates/includes/inline_post.html" %} | |||||
{% endfor %} | |||||
{% else %} | |||||
{% if limit_start %} | |||||
<div class="no-posts text-muted">No more posts.</div> | |||||
{% else %} | |||||
<div class="no-posts text-muted">Nothing posted yet.</div> | |||||
{% endif %} | |||||
{% endif %} |
@@ -1,8 +0,0 @@ | |||||
<tr class="sitemap-permission" data-user="{{ user.name }}"> | |||||
<td> | |||||
{% include "templates/includes/user_display.html" %} | |||||
</td> | |||||
<td><input type="checkbox" data-perm="read" {% if user.read %}checked{% endif %}></td> | |||||
<td><input type="checkbox" data-perm="write" {% if user.write %}checked{% endif %}></td> | |||||
<td><input type="checkbox" data-perm="admin" {% if user.admin %}checked{% endif %}></td> | |||||
</tr> |
@@ -1,9 +0,0 @@ | |||||
<div class="media"> | |||||
<div class="pull-left"> | |||||
<img class="media-object" src="{{ user.user_image }}" style="width: 50px; min-height: 1px"/> | |||||
</div> | |||||
<div class="media-body"> | |||||
<div>{{ user.first_name or "" }} {{ user.last_name or "" }}</div> | |||||
<div class="text-muted"><small>{{ user.location or "" }}</small></div> | |||||
</div> | |||||
</div> |
@@ -4,6 +4,8 @@ | |||||
background-image: none; | background-image: none; | ||||
border: none; | border: none; | ||||
border-bottom: 1px solid {{ get_shade(theme.top_bar_color, 10) }}; | border-bottom: 1px solid {{ get_shade(theme.top_bar_color, 10) }}; | ||||
padding-top: 15px; | |||||
padding-bottom: 15px; | |||||
} | } | ||||
.navbar .navbar-text, | .navbar .navbar-text, | ||||
@@ -12,11 +14,9 @@ | |||||
.navbar .nav > li > a { | .navbar .nav > li > a { | ||||
color: {{ theme.top_bar_text_color }}; | color: {{ theme.top_bar_text_color }}; | ||||
text-shadow: none; | text-shadow: none; | ||||
padding-top: 25px; | |||||
padding-bottom: 25px; | |||||
} | } | ||||
{# links #} | |||||
/* navbar links */ | |||||
.navbar .navbar-brand:hover, | .navbar .navbar-brand:hover, | ||||
.navbar .navbar-brand:focus, | .navbar .navbar-brand:focus, | ||||
.navbar .navbar-brand:active, | .navbar .navbar-brand:active, | ||||
@@ -29,7 +29,11 @@ | |||||
.navbar .navbar-link:active, | .navbar .navbar-link:active, | ||||
.navbar .nav > li > a:hover, | .navbar .nav > li > a:hover, | ||||
.navbar .nav > li > a:focus, | .navbar .nav > li > a:focus, | ||||
.navbar .nav > li > a:active { | |||||
.navbar .nav > li > a:active, | |||||
.navbar .nav > .open > a, | |||||
.navbar .nav > .open > a:hover, | |||||
.navbar .nav > .open > a:focus, | |||||
.navbar .nav > .open > a:active { | |||||
color: {{ get_shade(theme.top_bar_text_color, 15) }}; | color: {{ get_shade(theme.top_bar_text_color, 15) }}; | ||||
background-color: transparent; | background-color: transparent; | ||||
-webkit-box-shadow: none; | -webkit-box-shadow: none; | ||||
@@ -54,7 +58,7 @@ | |||||
border-radius: 0px; | border-radius: 0px; | ||||
} | } | ||||
{# navbar brand #} | |||||
/* navbar brand */ | |||||
.navbar-brand { | .navbar-brand { | ||||
padding-right: 30px; | padding-right: 30px; | ||||
max-width: 80%; | max-width: 80%; | ||||
@@ -63,8 +67,8 @@ | |||||
} | } | ||||
@media (max-width: 767px) { | @media (max-width: 767px) { | ||||
.toggle-sidebar { | |||||
padding: 25px 15px; | |||||
.navbar .toggle-sidebar { | |||||
padding: 10px 15px; | |||||
} | } | ||||
} | } | ||||
@@ -74,3 +78,28 @@ | |||||
} | } | ||||
} | } | ||||
/* navbar dropdowns */ | |||||
.navbar .dropdown.logged-in .avatar { | |||||
margin: 0px; | |||||
} | |||||
.nav .dropdown.logged-in .full-name { | |||||
line-height: 22px; | |||||
} | |||||
.nav .dropdown-menu > li > a { | |||||
padding: 14px; | |||||
} | |||||
.nav .dropdown-menu { | |||||
min-width: 200px; | |||||
padding: 0px; | |||||
font-size: 85%; | |||||
// only rounded bottoms | |||||
border-radius: 0px 0px 4px 4px; | |||||
} | |||||
.nav .dropdown-menu .divider { | |||||
margin: 0px; | |||||
} |
@@ -1,64 +0,0 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe, re | |||||
from frappe import _ | |||||
from frappe.utils import global_date_format | |||||
page_title = "Blog" | |||||
def get_context(context): | |||||
context.update(frappe.get_doc("Blog Settings", "Blog Settings").as_dict()) | |||||
context.children = get_children() | |||||
context.posts = get_blog_list(category=context.category, by=frappe.form_dict.by) | |||||
def get_children(context=None): | |||||
return frappe.db.sql("""select concat("blog/", page_name) as name, | |||||
title from `tabBlog Category` | |||||
where ifnull(published, 0) = 1 order by title asc""", as_dict=1) | |||||
@frappe.whitelist(allow_guest=True) | |||||
def get_blog_list(start=0, by=None, category=None): | |||||
condition = "" | |||||
if by: | |||||
condition = " and t1.blogger='%s'" % by.replace("'", "\'") | |||||
if category: | |||||
condition += " and t1.blog_category='%s'" % category.replace("'", "\'") | |||||
query = """\ | |||||
select | |||||
t1.title, t1.name, | |||||
concat(t1.parent_website_route, "/", t1.page_name) as page_name, | |||||
t1.published_on as creation, | |||||
day(t1.published_on) as day, monthname(t1.published_on) as month, | |||||
year(t1.published_on) as year, | |||||
ifnull(t1.blog_intro, t1.content) as content, | |||||
t2.full_name, t2.avatar, t1.blogger, | |||||
(select count(name) from `tabComment` where | |||||
comment_doctype='Blog Post' and comment_docname=t1.name) as comments | |||||
from `tabBlog Post` t1, `tabBlogger` t2 | |||||
where ifnull(t1.published,0)=1 | |||||
and t1.blogger = t2.name | |||||
%(condition)s | |||||
order by published_on desc, name asc | |||||
limit %(start)s, 20""" % {"start": start, "condition": condition} | |||||
posts = frappe.db.sql(query, as_dict=1) | |||||
for post in posts: | |||||
post.published = global_date_format(post.creation) | |||||
post.content = re.sub('\<[^>]*\>', '', post.content[:140]) | |||||
if not post.comments: | |||||
post.comment_text = _('No comments yet') | |||||
elif post.comments==1: | |||||
post.comment_text = _('1 comment') | |||||
else: | |||||
post.comment_text = _('{0} comments').format(str(post.comments)) | |||||
post.avatar = post.avatar or "" | |||||
if (not "http:" in post.avatar or "https:" in post.avatar) and not post.avatar.startswith("/"): | |||||
post.avatar = "/" + post.avatar | |||||
post.month = post.month.upper()[:3] | |||||
return frappe.render_template("templates/includes/blog_list.html", {"posts": posts}) |
@@ -1,4 +1,4 @@ | |||||
{% block style %}{% include "templates/includes/login.css" %}{% endblock %} | |||||
{% block style %}{% include "templates/includes/login/login.css" %}{% endblock %} | |||||
{% block content %} | {% block content %} | ||||
<div class="login-content container" style="max-width: 800px;"> | <div class="login-content container" style="max-width: 800px;"> | ||||
@@ -1,84 +1,9 @@ | |||||
{% block title %}{{ doctype }} {{ _("List") }}{% endblock %} | |||||
{% block title %}{{ title or (_("{0} List").format(_(doctype))) }}{% endblock %} | |||||
{% block header %} | |||||
<h2>{{ doctype }} {{ _("List") }}</h2> | |||||
{% endblock %} | |||||
{% block header %}<h2>{{ title or (_("{0} List").format(_(doctype))) }}</h2>{% endblock %} | |||||
{% block content %} | |||||
<div class="row"> | |||||
<div class=" col-sm-offset-8 col-sm-4"> | |||||
<form class="form-inline form-search" action="/list"> | |||||
<div class="input-group"> | |||||
<input class="form-control" doctype="text" name="txt" | |||||
placeholder="Search..." value="{{ txt or '' }}"> | |||||
<input type="hidden" name="doctype" value="{{ doctype }}"> | |||||
<span class="input-group-btn"> | |||||
<button class="btn btn-default" type="submit"> | |||||
<i class="icon-search"></i></button> | |||||
</span> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<br> | |||||
{% if txt %} | |||||
<div class="alert alert-warning">Results filtered by <b>{{ txt }}</b>. <a href="/list?doctype={{ doctype }}" class="close">×</a></div> | |||||
{% endif %} | |||||
<div data-doctype="{{ doctype }}" data-txt="{{ txt or '[notxt]' }}"> | |||||
{% for item in items %} | |||||
<div> | |||||
{{ item }} | |||||
</div> | |||||
</div> | |||||
{% endfor %} | |||||
</div> | |||||
<div class="more-block text-center hide"> | |||||
<button class="btn btn-default btn-more">More</button> | |||||
</div> | |||||
{% endblock %} | |||||
{% block content %}{% include "templates/includes/list/list.html" %}{% endblock %} | |||||
{% block script %} | |||||
<script> | |||||
frappe.ready(function() { | |||||
// show more button if len is 20 | |||||
$list_group = $(".list-group[data-doctype='{{ doctype }}'][data-txt='{{ txt or "[notxt]" }}']"); | |||||
{% block script %}{% include "templates/includes/list/list.js" %}{% endblock %} | |||||
// more ajax | |||||
frappe.start = 20; | |||||
$(".btn-more").on("click", function() { | |||||
$.ajax({ | |||||
url:"/api/method/frappe.templates.pages.list.get_items", | |||||
data: { | |||||
doctype: "{{ doctype }}", | |||||
txt: "{{ txt or '' }}", | |||||
limit_start: frappe.start | |||||
}, | |||||
statusCode: { | |||||
200: function(data) { | |||||
frappe.start += 20; | |||||
$.each(data.message.items, function(i, d) { | |||||
$('<div class="list-group-item">') | |||||
.html(d) | |||||
.appendTo($list_group); | |||||
}); | |||||
show_more(); | |||||
} | |||||
} | |||||
}) | |||||
}) | |||||
var show_more = function() { | |||||
var $items = $list_group.find(".list-group-item") | |||||
if($items.length && ($items.length % 20 === 0)) { | |||||
if($(".more-block").hasClass("hide")) | |||||
$(".more-block").removeClass("hide"); | |||||
} else { | |||||
if(!$(".more-block").hasClass("hide")) | |||||
$(".more-block").addClass("hide"); | |||||
} | |||||
}; | |||||
show_more(); | |||||
}) | |||||
</script> | |||||
{% endblock %} | |||||
{% block style %}{% include "templates/includes/list/list.css" %}{% endblock %} |
@@ -2,26 +2,68 @@ | |||||
# MIT License. See license.txt | # MIT License. See license.txt | ||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe, os | |||||
from frappe.modules import get_doc_path, load_doctype_module | |||||
from jinja2 import Template | |||||
import frappe | |||||
from frappe.model.base_document import get_controller | |||||
from frappe.utils import cint | |||||
no_cache = 1 | no_cache = 1 | ||||
no_sitemap = 1 | no_sitemap = 1 | ||||
def get_context(context): | def get_context(context): | ||||
context.doctype = frappe.local.form_dict.doctype | |||||
doctype = frappe.local.form_dict.doctype | |||||
context.update(get_list_context(context, doctype) or {}) | |||||
context.doctype = doctype | |||||
context.txt = frappe.local.form_dict.txt | context.txt = frappe.local.form_dict.txt | ||||
module = load_doctype_module(context.doctype) | |||||
context.update(get_items(context.doctype, context.txt)) | |||||
context.update(get(**frappe.local.form_dict)) | |||||
return context | return context | ||||
def get_list_context(context, doctype): | |||||
controller = get_controller(doctype) | |||||
if hasattr(controller, "get_list_context"): | |||||
return controller.get_list_context(context) | |||||
@frappe.whitelist(allow_guest=True) | @frappe.whitelist(allow_guest=True) | ||||
def get_items(doctype, txt, limit_start=0): | |||||
def get(doctype, txt=None, limit_start=0, **kwargs): | |||||
limit_start = cint(limit_start) | |||||
limit_page_length = 20 | |||||
next_start = limit_start + limit_page_length | |||||
filters = frappe._dict(kwargs) | |||||
controller = get_controller(doctype) | |||||
meta = frappe.get_meta(doctype) | meta = frappe.get_meta(doctype) | ||||
filters, or_filters = [], [] | |||||
out = frappe._dict() | |||||
module = load_doctype_module(doctype) | |||||
list_context = frappe._dict(hasattr(controller, "get_list_context") and controller.get_list_context() or {}) | |||||
_get_list = list_context.get_list or get_list | |||||
raw_result = _get_list(doctype=doctype, txt=txt, filters=filters, | |||||
limit_start=limit_start, limit_page_length=limit_page_length) | |||||
show_more = (_get_list(doctype=doctype, txt=txt, filters=filters, | |||||
limit_start=next_start, limit_page_length=1) | |||||
and True or False) | |||||
result = [] | |||||
row_template = list_context.row_template or "templates/includes/list/row_template.html" | |||||
for item in raw_result: | |||||
item.doctype = doctype | |||||
item.update(list_context) | |||||
result.append(frappe.render_template(row_template, | |||||
{ "doc": item, "meta": meta, "pathname": frappe.local.request.path.strip("/ ") }, | |||||
is_path=True)) | |||||
return { | |||||
"result": result, | |||||
"show_more": show_more, | |||||
"next_start": next_start | |||||
} | |||||
def get_list(doctype, txt, filters, limit_start, limit_page_length=20, ignore_permissions=False): | |||||
meta = frappe.get_meta(doctype) | |||||
if not filters: | |||||
filters = [] | |||||
or_filters = [] | |||||
if txt: | if txt: | ||||
if meta.search_fields: | if meta.search_fields: | ||||
@@ -30,23 +72,7 @@ def get_items(doctype, txt, limit_start=0): | |||||
else: | else: | ||||
filters.append([doctype, "name", "like", "%" + txt + "%"]) | filters.append([doctype, "name", "like", "%" + txt + "%"]) | ||||
return frappe.get_list(doctype, fields = ["*"], | |||||
filters=filters, or_filters=or_filters, limit_start=limit_start, | |||||
limit_page_length = limit_page_length, ignore_permissions=ignore_permissions) | |||||
out.raw_items = frappe.get_list(doctype, fields = ["*"], | |||||
filters=filters, or_filters = or_filters, limit_start=limit_start, | |||||
limit_page_length = 20) | |||||
if hasattr(module, "get_list_item"): | |||||
out["items"] = [] | |||||
for i in out.raw_items: | |||||
i.doc = i | |||||
out["items"].append(module.get_list_item(i)) | |||||
else: | |||||
template = Template("""<div><a href="/{{ doctype }}/{{ doc.name }}" no-pjax> | |||||
{{ doc[title_field] }}</a></div>""") | |||||
out.items = [template.render(doc=i, doctype=doctype, | |||||
title_field = meta.title_field or "name") for i in out.raw_items] | |||||
out.meta = meta | |||||
return out |
@@ -1,4 +1,4 @@ | |||||
{% block style %}{% include "templates/includes/login.css" %}{% endblock %} | |||||
{% block style %}{% include "templates/includes/login/login.css" %}{% endblock %} | |||||
{% block content %} | {% block content %} | ||||
<!-- no-header --> | <!-- no-header --> | ||||
@@ -70,6 +70,6 @@ | |||||
</div> | </div> | ||||
{% endblock %} | {% endblock %} | ||||
{% block script_lib %}{% include "templates/includes/login.js" %}{% endblock %} | |||||
{% block script_lib %}{% include "templates/includes/login/login.js" %}{% endblock %} | |||||
{% block sidebar %}{% endblock %} | {% block sidebar %}{% endblock %} |
@@ -0,0 +1,55 @@ | |||||
{% block title %}{{ _("My Account") }}{% endblock %} | |||||
{% block content %} | |||||
<!-- no-header --> | |||||
<div class="row"> | |||||
<div class="col-sm-3"> | |||||
<div class="your-account-info"> | |||||
<div class="avatar avatar-large"> | |||||
<a href="/user"><img class="user-image" src="{{ user_image }}" /></a> | |||||
</div> | |||||
<div> | |||||
<h4><a href="/user">{{ fullname }}</a></h4> | |||||
<ul class="list-unstyled small user-options"> | |||||
<li><a href="">{{ _("Reset Password") }}</a></li> | |||||
<li><a href="">{{ _("Logout") }}</a></li> | |||||
</ul> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="col-sm-9"> | |||||
<ul class="list-unstyled my-account-list"> | |||||
{% for opts in my_account_list -%} | |||||
<li><a href="{{ opts.url }}">{{ opts.label }}</a></li> | |||||
{%- endfor %} | |||||
</ul> | |||||
</div> | |||||
</div> | |||||
{% endblock %} | |||||
{% block style %} | |||||
<style> | |||||
.your-account-info { | |||||
margin: 15px 0px; | |||||
} | |||||
.my-account-list { | |||||
margin: 0px 0px 15px; | |||||
} | |||||
.my-account-list > li > a { | |||||
margin: 15px 0px; | |||||
display: inline-block; | |||||
} | |||||
.user-options { | |||||
margin-top: 15px; | |||||
} | |||||
.user-options > li > a { | |||||
margin: 5px 0px; | |||||
display: inline-block; | |||||
} | |||||
</style> | |||||
{% endblock %} |
@@ -0,0 +1,23 @@ | |||||
# Copyright (c) 2015, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
from frappe import _ | |||||
from frappe.utils.user import get_fullname_and_avatar | |||||
no_cache = 1 | |||||
no_sitemap = 1 | |||||
def get_context(context): | |||||
if frappe.session.user == "Guest": | |||||
frappe.throw(_("You need to be logged in to access this page."), frappe.PermissionError) | |||||
context["my_account_list"] = [] | |||||
for method in frappe.get_hooks("my_account_context"): | |||||
frappe.get_attr(method)(context) | |||||
info = get_fullname_and_avatar(frappe.session.user) | |||||
context["fullname"] = info.fullname | |||||
context["user_image"] = info.avatar |
@@ -120,7 +120,9 @@ def validate_print_permission(doc): | |||||
return | return | ||||
for ptype in ("read", "print"): | for ptype in ("read", "print"): | ||||
if not frappe.has_permission(doc.doctype, ptype, doc): | |||||
if (not frappe.has_permission(doc.doctype, ptype, doc) | |||||
and not frappe.has_website_permission(doc.doctype, ptype, doc)): | |||||
raise frappe.PermissionError(_("No {0} permission").format(ptype)) | raise frappe.PermissionError(_("No {0} permission").format(ptype)) | ||||
def get_letter_head(doc, no_letterhead): | def get_letter_head(doc, no_letterhead): | ||||
@@ -13,8 +13,9 @@ def get_context(context): | |||||
script_context = { "javascript": frappe.db.get_value('Website Script', None, 'javascript') } | script_context = { "javascript": frappe.db.get_value('Website Script', None, 'javascript') } | ||||
theme = get_active_theme() | theme = get_active_theme() | ||||
if strip(theme.javascript or ""): | |||||
script_context["javascript"] += "\n" + strip(theme.javascript) | |||||
js = strip(theme.js or "") | |||||
if js: | |||||
script_context["javascript"] += "\n" + js | |||||
if not frappe.conf.developer_mode: | if not frappe.conf.developer_mode: | ||||
script_context["google_analytics_id"] = frappe.db.get_value("Website Settings", "Website Settings", | script_context["google_analytics_id"] = frappe.db.get_value("Website Settings", "Website Settings", | ||||
@@ -38,7 +38,7 @@ a { | |||||
a:hover, | a:hover, | ||||
a:focus, | a:focus, | ||||
a:active { | a:active { | ||||
color: {{ get_shade(theme.link_color, 5) }}; | |||||
color: {{ get_shade(theme.link_color, 25) }}; | |||||
} | } | ||||
{# headings #} | {# headings #} | ||||
@@ -6,10 +6,10 @@ | |||||
<p>{{ writers_introduction }}</p> | <p>{{ writers_introduction }}</p> | ||||
{% endif %} | {% endif %} | ||||
{% for blogger_info in bloggers %} | {% for blogger_info in bloggers %} | ||||
{% include "templates/includes/blogger.html" %} | |||||
{% include "templates/includes/blog/blogger.html" %} | |||||
{% if not loop.last %}<hr>{% endif %} | {% if not loop.last %}<hr>{% endif %} | ||||
{% endfor %} | {% endfor %} | ||||
</div> | </div> | ||||
{% endblock %} | {% endblock %} | ||||
{% block footer %}{% include "templates/includes/blog_footer.html" %}{% endblock %} | |||||
{% block footer %}{% include "templates/includes/blog/blog_footer.html" %}{% endblock %} |
@@ -164,6 +164,12 @@ def get_datetime_str(datetime_obj): | |||||
return datetime_obj.strftime(DATETIME_FORMAT) | return datetime_obj.strftime(DATETIME_FORMAT) | ||||
def get_user_format(): | |||||
if getattr(frappe.local, "user_format", None) is None: | |||||
frappe.local.user_format = frappe.db.get_default("date_format") | |||||
return frappe.local.user_format or "yyyy-mm-dd" | |||||
def formatdate(string_date=None, format_string=None): | def formatdate(string_date=None, format_string=None): | ||||
""" | """ | ||||
Convers the given string date to :data:`user_format` | Convers the given string date to :data:`user_format` | ||||
@@ -176,21 +182,20 @@ def formatdate(string_date=None, format_string=None): | |||||
* dd/mm/yyyy | * dd/mm/yyyy | ||||
""" | """ | ||||
date = getdate(string_date) if string_date else now_datetime().date() | date = getdate(string_date) if string_date else now_datetime().date() | ||||
if not format_string: | |||||
format_string = get_user_format().replace("mm", "MM") | |||||
if format_string: | |||||
return babel.dates.format_date(date, format_string or "medium", locale=(frappe.local.lang or "").replace("-", "_")) | |||||
else: | |||||
if getattr(frappe.local, "user_format", None) is None: | |||||
frappe.local.user_format = frappe.db.get_default("date_format") | |||||
return babel.dates.format_date(date, format_string, locale=(frappe.local.lang or "").replace("-", "_")) | |||||
def format_datetime(datetime_string, format_string=None): | |||||
if not datetime_string: | |||||
return | |||||
out = frappe.local.user_format or "yyyy-mm-dd" | |||||
datetime = get_datetime(datetime_string) | |||||
if not format_string: | |||||
format_string = get_user_format().replace("mm", "MM") + " hh:mm:ss" | |||||
try: | |||||
return out.replace("dd", date.strftime("%d"))\ | |||||
.replace("mm", date.strftime("%m"))\ | |||||
.replace("yyyy", date.strftime("%Y")) | |||||
except ValueError, e: | |||||
raise frappe.ValidationError, str(e) | |||||
return babel.dates.format_datetime(datetime, format_string, locale=(frappe.local.lang or "").replace("-", "_")) | |||||
def global_date_format(date): | def global_date_format(date): | ||||
"""returns date as 1 January 2012""" | """returns date as 1 January 2012""" | ||||
@@ -3,7 +3,7 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe | import frappe | ||||
from frappe.utils import formatdate, fmt_money, flt, cstr, cint | |||||
from frappe.utils import formatdate, fmt_money, flt, cstr, cint, format_datetime | |||||
from frappe.model.meta import get_field_currency, get_field_precision | from frappe.model.meta import get_field_currency, get_field_precision | ||||
import re | import re | ||||
@@ -11,10 +11,13 @@ def format_value(value, df, doc=None, currency=None): | |||||
# Convert dict to object if necessary | # Convert dict to object if necessary | ||||
if (isinstance(df, dict)): | if (isinstance(df, dict)): | ||||
df = frappe._dict(df) | df = frappe._dict(df) | ||||
if df.get("fieldtype")=="Date": | if df.get("fieldtype")=="Date": | ||||
return formatdate(value) | return formatdate(value) | ||||
elif df.get("fieldtype")=="Datetime": | |||||
return format_datetime(value) | |||||
elif df.get("fieldtype") == "Currency" or (df.get("fieldtype")=="Float" and (df.options or "").strip()): | elif df.get("fieldtype") == "Currency" or (df.get("fieldtype")=="Float" and (df.options or "").strip()): | ||||
return fmt_money(value, precision=get_field_precision(df, doc), | return fmt_money(value, precision=get_field_precision(df, doc), | ||||
currency=currency if currency else (get_field_currency(df, doc) if doc else None)) | currency=currency if currency else (get_field_currency(df, doc) if doc else None)) | ||||
@@ -4,6 +4,7 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe, json | import frappe, json | ||||
from frappe import _dict | |||||
class User: | class User: | ||||
""" | """ | ||||
@@ -30,6 +31,7 @@ class User: | |||||
self.can_set_user_permissions = [] | self.can_set_user_permissions = [] | ||||
self.allow_modules = [] | self.allow_modules = [] | ||||
self.in_create = [] | self.in_create = [] | ||||
self.doc = frappe.get_doc("User", self.name) | |||||
def get_roles(self): | def get_roles(self): | ||||
"""get list of roles""" | """get list of roles""" | ||||
@@ -167,10 +169,10 @@ def get_user_fullname(user): | |||||
def get_fullname_and_avatar(user): | def get_fullname_and_avatar(user): | ||||
first_name, last_name, avatar = frappe.db.get_value("User", | first_name, last_name, avatar = frappe.db.get_value("User", | ||||
user, ["first_name", "last_name", "user_image"]) | user, ["first_name", "last_name", "user_image"]) | ||||
return { | |||||
return _dict({ | |||||
"fullname": " ".join(filter(None, [first_name, last_name])), | "fullname": " ".join(filter(None, [first_name, last_name])), | ||||
"avatar": avatar | "avatar": avatar | ||||
} | |||||
}) | |||||
def get_system_managers(only_name=False): | def get_system_managers(only_name=False): | ||||
"""returns all system manager's user details""" | """returns all system manager's user details""" | ||||
@@ -234,3 +236,6 @@ def get_roles(user=None, with_standard=True): | |||||
def get_enabled_system_users(): | def get_enabled_system_users(): | ||||
return frappe.db.sql("""select * from tabUser where | return frappe.db.sql("""select * from tabUser where | ||||
user_type='System User' and enabled=1 and name not in ('Administrator', 'Guest')""", as_dict=1) | user_type='System User' and enabled=1 and name not in ('Administrator', 'Guest')""", as_dict=1) | ||||
def is_website_user(user): | |||||
return frappe.get_user(user).doc.user_type == "Website User" |
@@ -46,6 +46,7 @@ def build_context(context): | |||||
# provide doc | # provide doc | ||||
if context.doc: | if context.doc: | ||||
context.update(context.doc.as_dict()) | context.update(context.doc.as_dict()) | ||||
context.update(context.doc.website) | |||||
if hasattr(context.doc, "get_context"): | if hasattr(context.doc, "get_context"): | ||||
ret = context.doc.get_context(context) | ret = context.doc.get_context(context) | ||||
if ret: | if ret: | ||||
@@ -8,9 +8,6 @@ from frappe.website.render import clear_cache | |||||
from frappe.templates.pages.blog import get_context | from frappe.templates.pages.blog import get_context | ||||
class BlogCategory(WebsiteGenerator): | class BlogCategory(WebsiteGenerator): | ||||
page_title_field = "title" | |||||
template = "templates/generators/blog_category.html" | |||||
no_cache = True | |||||
def autoname(self): | def autoname(self): | ||||
# to override autoname of WebsiteGenerator | # to override autoname of WebsiteGenerator | ||||
self.name = self.category_name | self.name = self.category_name | ||||
@@ -22,8 +19,3 @@ class BlogCategory(WebsiteGenerator): | |||||
def validate(self): | def validate(self): | ||||
self.parent_website_route = "blog" | self.parent_website_route = "blog" | ||||
super(BlogCategory, self).validate() | super(BlogCategory, self).validate() | ||||
def get_context(self, context): | |||||
"""Build context from `frappe.templates.pages.blog`""" | |||||
context.category = self.name | |||||
get_context(context) |
@@ -4,20 +4,21 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe, re | import frappe, re | ||||
from frappe import _ | |||||
from frappe.website.website_generator import WebsiteGenerator | from frappe.website.website_generator import WebsiteGenerator | ||||
from frappe.website.render import clear_cache | from frappe.website.render import clear_cache | ||||
from frappe.utils import today, cint, global_date_format, get_fullname | from frappe.utils import today, cint, global_date_format, get_fullname | ||||
from frappe.website.utils import find_first_image, get_comment_list | from frappe.website.utils import find_first_image, get_comment_list | ||||
from frappe.templates.pages.blog import get_children | |||||
class BlogPost(WebsiteGenerator): | class BlogPost(WebsiteGenerator): | ||||
condition_field = "published" | |||||
template = "templates/generators/blog_post.html" | |||||
save_versions = True | save_versions = True | ||||
order_by = "published_on desc" | |||||
parent_website_route_field = "blog_category" | |||||
page_title_field = "title" | |||||
website = frappe._dict( | |||||
condition_field = "published", | |||||
template = "templates/generators/blog_post.html", | |||||
order_by = "published_on desc", | |||||
parent_website_route_field = "blog_category", | |||||
page_title_field = "title" | |||||
) | |||||
def get_feed(self): | def get_feed(self): | ||||
return self.title | return self.title | ||||
@@ -74,6 +75,24 @@ class BlogPost(WebsiteGenerator): | |||||
context.children = get_children() | context.children = get_children() | ||||
@staticmethod | |||||
def get_list_context(context=None): | |||||
list_context = frappe._dict( | |||||
page_title = _("Blog"), | |||||
template = "templates/includes/blog/blog.html", | |||||
row_template = "templates/includes/blog/blog_row.html", | |||||
get_list = get_blog_list, | |||||
hide_filters = True, | |||||
children = get_children() | |||||
) | |||||
list_context.update(frappe.get_doc("Blog Settings", "Blog Settings").as_dict()) | |||||
return list_context | |||||
def get_children(): | |||||
return frappe.db.sql("""select concat("blog/", page_name) as name, | |||||
title from `tabBlog Category` | |||||
where ifnull(published, 0) = 1 order by title asc""", as_dict=1) | |||||
def clear_blog_cache(): | def clear_blog_cache(): | ||||
for blog in frappe.db.sql_list("""select page_name from | for blog in frappe.db.sql_list("""select page_name from | ||||
`tabBlog Post` where ifnull(published,0)=1"""): | `tabBlog Post` where ifnull(published,0)=1"""): | ||||
@@ -81,3 +100,54 @@ def clear_blog_cache(): | |||||
clear_cache("writers") | clear_cache("writers") | ||||
def get_blog_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20): | |||||
condition = "" | |||||
if filters: | |||||
if filters.by: | |||||
condition = " and t1.blogger='%s'" % filters.by.replace("'", "\'") | |||||
if filters.category: | |||||
condition += " and t1.blog_category='%s'" % filters.category.replace("'", "\'") | |||||
if condition: | |||||
frappe.local.no_cache = 1 | |||||
query = """\ | |||||
select | |||||
t1.title, t1.name, | |||||
concat(t1.parent_website_route, "/", t1.page_name) as page_name, | |||||
t1.published_on as creation, | |||||
day(t1.published_on) as day, monthname(t1.published_on) as month, | |||||
year(t1.published_on) as year, | |||||
ifnull(t1.blog_intro, t1.content) as content, | |||||
t2.full_name, t2.avatar, t1.blogger, | |||||
(select count(name) from `tabComment` where | |||||
comment_doctype='Blog Post' and comment_docname=t1.name) as comments | |||||
from `tabBlog Post` t1, `tabBlogger` t2 | |||||
where ifnull(t1.published,0)=1 | |||||
and t1.blogger = t2.name | |||||
%(condition)s | |||||
order by published_on desc, name asc | |||||
limit %(start)s, %(page_len)s""" % { | |||||
"start": limit_start, "page_len": limit_page_length, "condition": condition | |||||
} | |||||
posts = frappe.db.sql(query, as_dict=1) | |||||
for post in posts: | |||||
post.published = global_date_format(post.creation) | |||||
post.content = re.sub('\<[^>]*\>', '', post.content[:140]) | |||||
if not post.comments: | |||||
post.comment_text = _('No comments yet') | |||||
elif post.comments==1: | |||||
post.comment_text = _('1 comment') | |||||
else: | |||||
post.comment_text = _('{0} comments').format(str(post.comments)) | |||||
post.avatar = post.avatar or "" | |||||
if (not "http:" in post.avatar or "https:" in post.avatar) and not post.avatar.startswith("/"): | |||||
post.avatar = "/" + post.avatar | |||||
post.month = post.month.upper()[:3] | |||||
return posts |
@@ -8,10 +8,12 @@ from frappe import _ | |||||
from frappe.utils.file_manager import save_file, remove_file_by_url | from frappe.utils.file_manager import save_file, remove_file_by_url | ||||
class WebForm(WebsiteGenerator): | class WebForm(WebsiteGenerator): | ||||
template = "templates/generators/web_form.html" | |||||
condition_field = "published" | |||||
page_title_field = "title" | |||||
no_cache = 1 | |||||
website = frappe._dict( | |||||
template = "templates/generators/web_form.html", | |||||
condition_field = "published", | |||||
page_title_field = "title", | |||||
no_cache = 1 | |||||
) | |||||
def get_context(self, context): | def get_context(self, context): | ||||
context.params = frappe.form_dict | context.params = frappe.form_dict | ||||
@@ -14,10 +14,12 @@ from jinja2.exceptions import TemplateSyntaxError | |||||
class WebPage(WebsiteGenerator): | class WebPage(WebsiteGenerator): | ||||
save_versions = True | save_versions = True | ||||
template = "templates/generators/web_page.html" | |||||
condition_field = "published" | |||||
page_title_field = "title" | |||||
parent_website_route_field = "parent_web_page" | |||||
website = frappe._dict( | |||||
template = "templates/generators/web_page.html", | |||||
condition_field = "published", | |||||
page_title_field = "title", | |||||
parent_website_route_field = "parent_web_page" | |||||
) | |||||
def get_feed(self): | def get_feed(self): | ||||
return self.title | return self.title | ||||
@@ -85,8 +85,9 @@ def get_website_settings(): | |||||
where parent='Website Settings' and parentfield='footer_items' | where parent='Website Settings' and parentfield='footer_items' | ||||
order by idx asc""", as_dict=1), | order by idx asc""", as_dict=1), | ||||
"post_login": [ | "post_login": [ | ||||
{"label": "Reset Password", "url": "update-password", "icon": "icon-key"}, | |||||
{"label": "Logout", "url": "/?cmd=web_logout", "icon": "icon-signout"} | |||||
{"label": "My Account", "url": "/me"}, | |||||
{"class": "divider"}, | |||||
{"label": "Logout", "url": "/?cmd=web_logout"} | |||||
] | ] | ||||
}) | }) | ||||
@@ -112,8 +113,8 @@ def get_website_settings(): | |||||
context.encoded_title = quote(encode(context.title or ""), str("")) | context.encoded_title = quote(encode(context.title or ""), str("")) | ||||
for update_website_context in hooks.update_website_context or []: | |||||
frappe.get_attr(update_website_context)(context) | |||||
for update_website_params in hooks.update_website_params or []: | |||||
frappe.get_attr(update_website_params)(context) | |||||
context.web_include_js = hooks.web_include_js or [] | context.web_include_js = hooks.web_include_js or [] | ||||
@@ -64,6 +64,8 @@ def add_website_theme(context): | |||||
bootstrap = frappe.get_hooks("bootstrap")[0] | bootstrap = frappe.get_hooks("bootstrap")[0] | ||||
website_theme = get_active_theme() | website_theme = get_active_theme() | ||||
if website_theme: | if website_theme: | ||||
context.website_theme = website_theme | |||||
if website_theme.bootstrap: | if website_theme.bootstrap: | ||||
bootstrap = website_theme.bootstrap | bootstrap = website_theme.bootstrap | ||||
@@ -192,7 +192,7 @@ $.extend(frappe, { | |||||
$(".btn-login-area").toggle(false); | $(".btn-login-area").toggle(false); | ||||
$(".logged-in").toggle(true); | $(".logged-in").toggle(true); | ||||
$(".full-name").html(frappe.get_cookie("full_name")); | $(".full-name").html(frappe.get_cookie("full_name")); | ||||
$(".user-picture").attr("src", frappe.get_cookie("user_image")); | |||||
$(".user-image").attr("src", frappe.get_cookie("user_image")); | |||||
} | } | ||||
}, | }, | ||||
setup_push_state: function() { | setup_push_state: function() { | ||||
@@ -577,8 +577,7 @@ $(document).ready(function() { | |||||
// switch to app link | // switch to app link | ||||
if(getCookie("system_user")==="yes") { | if(getCookie("system_user")==="yes") { | ||||
$("#website-post-login .dropdown-menu").append('<li class="divider"></li>\ | |||||
<li><a href="/desk" no-pjax><i class="icon-fixed-width icon-th-large"></i> Switch To Desk</a></li>'); | |||||
$("#website-post-login .dropdown-menu").append('<li><a href="/desk" no-pjax>Switch To Desk</a></li>'); | |||||
} | } | ||||
frappe.render_user(); | frappe.render_user(); | ||||
@@ -7,6 +7,7 @@ from frappe import _ | |||||
from frappe.utils import cstr | from frappe.utils import cstr | ||||
import mimetypes, json | import mimetypes, json | ||||
from werkzeug.wrappers import Response | from werkzeug.wrappers import Response | ||||
from werkzeug.routing import Map, Rule, NotFound | |||||
from frappe.website.context import get_context | from frappe.website.context import get_context | ||||
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache, delete_page_cache | from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache, delete_page_cache | ||||
@@ -17,7 +18,6 @@ class PageNotFoundError(Exception): pass | |||||
def render(path, http_status_code=None): | def render(path, http_status_code=None): | ||||
"""render html page""" | """render html page""" | ||||
path = resolve_path(path.strip("/ ")) | path = resolve_path(path.strip("/ ")) | ||||
frappe.local.path = path | |||||
try: | try: | ||||
data = render_page(path) | data = render_page(path) | ||||
@@ -158,6 +158,28 @@ def resolve_path(path): | |||||
if path == "index": | if path == "index": | ||||
path = get_home_page() | path = get_home_page() | ||||
frappe.local.path = path | |||||
if path != "index": | |||||
path = resolve_from_map(path) | |||||
return path | |||||
def resolve_from_map(path): | |||||
m = Map([Rule(r["from_route"], endpoint=r["to_route"], defaults=r.get("defaults")) | |||||
for r in frappe.get_hooks("website_route_rules")]) | |||||
urls = m.bind_to_environ(frappe.local.request.environ) | |||||
try: | |||||
endpoint, args = urls.match("/" + path) | |||||
path = endpoint | |||||
if args: | |||||
# don't cache when there's a query string! | |||||
frappe.local.no_cache = 1 | |||||
frappe.local.form_dict.update(args) | |||||
except NotFound: | |||||
pass | |||||
return path | return path | ||||
def set_content_type(response, data, path): | def set_content_type(response, data, path): | ||||
@@ -28,7 +28,7 @@ def build_route(path): | |||||
context.doctype = context.ref_doctype | context.doctype = context.ref_doctype | ||||
context.title = context.page_title | context.title = context.page_title | ||||
context.pathname = path | |||||
context.pathname = frappe.local.path | |||||
return context | return context | ||||
@@ -26,7 +26,8 @@ def render_blocks(context): | |||||
template = frappe.get_template(template_path) | template = frappe.get_template(template_path) | ||||
for block, render in template.blocks.items(): | for block, render in template.blocks.items(): | ||||
out[block] = scrub_relative_urls(concat(render(template.new_context(context)))) | |||||
new_context = template.new_context(context) | |||||
out[block] = scrub_relative_urls(concat(render(new_context))) | |||||
_render_blocks(context["template"]) | _render_blocks(context["template"]) | ||||
@@ -26,7 +26,7 @@ def find_first_image(html): | |||||
return None | return None | ||||
def can_cache(no_cache=False): | def can_cache(no_cache=False): | ||||
return not (frappe.conf.disable_website_cache or no_cache) | |||||
return not (frappe.conf.disable_website_cache or getattr(frappe.local, "no_cache", False) or no_cache) | |||||
def get_comment_list(doctype, name): | def get_comment_list(doctype, name): | ||||
return frappe.db.sql("""select | return frappe.db.sql("""select | ||||
@@ -12,7 +12,10 @@ from frappe.modules import get_module_name | |||||
from frappe.website.router import get_page_route | from frappe.website.router import get_page_route | ||||
class WebsiteGenerator(Document): | class WebsiteGenerator(Document): | ||||
page_title_field = "name" | |||||
website = frappe._dict( | |||||
page_title_field = "name" | |||||
) | |||||
def autoname(self): | def autoname(self): | ||||
if self.meta.autoname != "hash": | if self.meta.autoname != "hash": | ||||
self.name = self.get_page_name() | self.name = self.get_page_name() | ||||
@@ -77,15 +80,16 @@ class WebsiteGenerator(Document): | |||||
clear_cache(self.get_route()) | clear_cache(self.get_route()) | ||||
def website_published(self): | def website_published(self): | ||||
if hasattr(self, "condition_field"): | |||||
return self.get(self.condition_field) and True or False | |||||
if self.website.condition_field: | |||||
return self.get(self.website.condition_field) and True or False | |||||
else: | else: | ||||
return True | return True | ||||
def set_parent_website_route(self): | def set_parent_website_route(self): | ||||
if hasattr(self, "parent_website_route_field"): | |||||
field = self.meta.get_field(self.parent_website_route_field) | |||||
parent = self.get(self.parent_website_route_field) | |||||
parent_website_route_field = self.website.parent_website_route_field | |||||
if parent_website_route_field: | |||||
field = self.meta.get_field(parent_website_route_field) | |||||
parent = self.get(parent_website_route_field) | |||||
if parent: | if parent: | ||||
self.parent_website_route = frappe.get_doc(field.options, | self.parent_website_route = frappe.get_doc(field.options, | ||||
parent).get_route() | parent).get_route() | ||||
@@ -121,11 +125,13 @@ class WebsiteGenerator(Document): | |||||
"docname": self.name, | "docname": self.name, | ||||
"page_name": self.get_page_name(), | "page_name": self.get_page_name(), | ||||
"controller": get_module_name(self.doctype, self.meta.module), | "controller": get_module_name(self.doctype, self.meta.module), | ||||
"template": self.template, | |||||
"parent_website_route": self.get("parent_website_route", ""), | |||||
"page_title": getattr(self, "page_title", None) or self.get(self.page_title_field) | |||||
}) | }) | ||||
route.update(self.website) | |||||
if not route.page_title: | |||||
route.page_title = self.get(self.website.page_title_field) | |||||
self.update_permissions(route) | self.update_permissions(route) | ||||
return route | return route | ||||
@@ -147,7 +153,7 @@ class WebsiteGenerator(Document): | |||||
parents = [] | parents = [] | ||||
me = self | me = self | ||||
while me: | while me: | ||||
_parent_field = getattr(me, "parent_website_route_field", None) | |||||
_parent_field = me.website.parent_website_route_field | |||||
_parent_val = me.get(_parent_field) if _parent_field else None | _parent_val = me.get(_parent_field) if _parent_field else None | ||||
# if no parent and not home page, then parent is home page | # if no parent and not home page, then parent is home page | ||||
@@ -165,7 +171,7 @@ class WebsiteGenerator(Document): | |||||
if parent_doc: | if parent_doc: | ||||
parent_info = frappe._dict(name = parent_doc.get_route(), | parent_info = frappe._dict(name = parent_doc.get_route(), | ||||
title= parent_doc.get(getattr(parent_doc, "page_title_field", "name"))) | |||||
title= parent_doc.get(parent_doc.website.page_title_field or "name")) | |||||
else: | else: | ||||
parent_info = frappe._dict(name=self.parent_website_route, | parent_info = frappe._dict(name=self.parent_website_route, | ||||
title=self.parent_website_route.replace("_", " ").title()) | title=self.parent_website_route.replace("_", " ").title()) | ||||
@@ -188,8 +194,9 @@ class WebsiteGenerator(Document): | |||||
return parents | return parents | ||||
def get_parent(self): | def get_parent(self): | ||||
if hasattr(self, "parent_website_route_field"): | |||||
return self.get(self.parent_website_route_field) | |||||
parent_website_route_field = self.website.parent_website_route_field | |||||
if parent_website_route_field: | |||||
return self.get(parent_website_route_field) | |||||
def get_children(self, context=None): | def get_children(self, context=None): | ||||
children = [] | children = [] | ||||
@@ -214,9 +221,9 @@ class WebsiteGenerator(Document): | |||||
where ifnull(parent_website_route,'')=%s | where ifnull(parent_website_route,'')=%s | ||||
order by {order_by}""".format( | order by {order_by}""".format( | ||||
doctype = self.doctype, | doctype = self.doctype, | ||||
title_field = getattr(self, "page_title_field", "name"), | |||||
order_by = getattr(self, "order_by", "idx asc")), | |||||
route, as_dict=True) | |||||
title_field = self.website.page_title_field or "name", | |||||
order_by = self.website.order_by or "idx asc" | |||||
), route, as_dict=True) | |||||
for c in children: | for c in children: | ||||
c.name = make_route(c) | c.name = make_route(c) | ||||