Parcourir la source

Website Listing

version-14
Anand Doshi il y a 10 ans
Parent
révision
7f75e233a8
90 fichiers modifiés avec 1368 ajouts et 987 suppressions
  1. +16
    -0
      frappe/__init__.py
  2. +4
    -0
      frappe/hooks.py
  3. +7
    -2
      frappe/model/base_document.py
  4. +2
    -2
      frappe/model/db_query.py
  5. +15
    -0
      frappe/model/meta.py
  6. +3
    -2
      frappe/patches/v5_0/style_settings_to_website_theme.py
  7. +30
    -30
      frappe/public/css/avatar.css
  8. +145
    -0
      frappe/public/css/common.css
  9. +93
    -54
      frappe/public/css/desk.css
  10. +1
    -0
      frappe/public/css/form_grid.css
  11. +8
    -3
      frappe/public/css/mobile.css
  12. +8
    -3
      frappe/public/css/offcanvas.css
  13. +8
    -3
      frappe/public/css/sidebar.css
  14. +230
    -111
      frappe/public/css/website.css
  15. +1
    -1
      frappe/public/js/frappe/form/footer/assign_to.js
  16. +1
    -1
      frappe/public/js/frappe/form/formatters.js
  17. +2
    -2
      frappe/public/js/frappe/form/share.js
  18. +32
    -3
      frappe/public/js/frappe/misc/user.js
  19. +3
    -2
      frappe/public/js/frappe/ui/toolbar/awesome_bar.js
  20. +1
    -1
      frappe/public/js/frappe/ui/toolbar/navbar.html
  21. +1
    -1
      frappe/public/js/frappe/ui/toolbar/offcanvas_left_sidebar.html
  22. +51
    -0
      frappe/public/less/avatar.less
  23. +156
    -0
      frappe/public/less/common.less
  24. +1
    -113
      frappe/public/less/desk.less
  25. +1
    -0
      frappe/public/less/form_grid.less
  26. +0
    -8
      frappe/public/less/navbar.less
  27. +8
    -2
      frappe/public/less/offcanvas.less
  28. +8
    -128
      frappe/public/less/website.less
  29. +5
    -5
      frappe/templates/base.html
  30. +3
    -3
      frappe/templates/generators/blog_post.html
  31. +1
    -1
      frappe/templates/generators/web_form.html
  32. +1
    -1
      frappe/templates/generators/web_page.html
  33. +0
    -60
      frappe/templates/includes/blog.js
  34. +4
    -7
      frappe/templates/includes/blog/blog.html
  35. +0
    -0
      frappe/templates/includes/blog/blog_footer.html
  36. +14
    -0
      frappe/templates/includes/blog/blog_row.html
  37. +0
    -0
      frappe/templates/includes/blog/blogger.html
  38. +0
    -16
      frappe/templates/includes/blog_list.html
  39. +6
    -2
      frappe/templates/includes/breadcrumbs.html
  40. +0
    -0
      frappe/templates/includes/comments/__init__.py
  41. +0
    -0
      frappe/templates/includes/comments/comment.html
  42. +2
    -2
      frappe/templates/includes/comments/comments.html
  43. +0
    -0
      frappe/templates/includes/comments/comments.py
  44. +2
    -2
      frappe/templates/includes/footer/footer.html
  45. +0
    -0
      frappe/templates/includes/footer/footer_extension.html
  46. +0
    -0
      frappe/templates/includes/footer/footer_powered.html
  47. +0
    -57
      frappe/templates/includes/inline_post.html
  48. +0
    -0
      frappe/templates/includes/list/__init__.py
  49. +22
    -0
      frappe/templates/includes/list/filters.html
  50. +31
    -0
      frappe/templates/includes/list/list.css
  51. +19
    -0
      frappe/templates/includes/list/list.html
  52. +31
    -0
      frappe/templates/includes/list/list.js
  53. +21
    -0
      frappe/templates/includes/list/row_template.html
  54. +0
    -0
      frappe/templates/includes/login/login.css
  55. +0
    -0
      frappe/templates/includes/login/login.js
  56. +1
    -1
      frappe/templates/includes/navbar/navbar.html
  57. +5
    -9
      frappe/templates/includes/navbar/navbar_items.html
  58. +0
    -0
      frappe/templates/includes/navbar/navbar_link.html
  59. +0
    -66
      frappe/templates/includes/post_editor.html
  60. +0
    -11
      frappe/templates/includes/post_list.html
  61. +0
    -8
      frappe/templates/includes/sitemap_permission.html
  62. +0
    -9
      frappe/templates/includes/user_display.html
  63. +36
    -7
      frappe/templates/includes/website_theme/navbar.css
  64. +0
    -64
      frappe/templates/pages/blog.py
  65. +1
    -1
      frappe/templates/pages/complete_signup.html
  66. +5
    -80
      frappe/templates/pages/list.html
  67. +55
    -29
      frappe/templates/pages/list.py
  68. +2
    -2
      frappe/templates/pages/login.html
  69. +55
    -0
      frappe/templates/pages/me.html
  70. +23
    -0
      frappe/templates/pages/me.py
  71. +3
    -1
      frappe/templates/pages/print.py
  72. +3
    -2
      frappe/templates/pages/website_script.py
  73. +1
    -1
      frappe/templates/pages/website_theme.css
  74. +2
    -2
      frappe/templates/pages/writers.html
  75. +17
    -12
      frappe/utils/data.py
  76. +5
    -2
      frappe/utils/formatters.py
  77. +7
    -2
      frappe/utils/user.py
  78. +1
    -0
      frappe/website/context.py
  79. +0
    -8
      frappe/website/doctype/blog_category/blog_category.py
  80. +77
    -7
      frappe/website/doctype/blog_post/blog_post.py
  81. +6
    -4
      frappe/website/doctype/web_form/web_form.py
  82. +6
    -4
      frappe/website/doctype/web_page/web_page.py
  83. +5
    -4
      frappe/website/doctype/website_settings/website_settings.py
  84. +2
    -0
      frappe/website/doctype/website_theme/website_theme.py
  85. +2
    -3
      frappe/website/js/website.js
  86. +23
    -1
      frappe/website/render.py
  87. +1
    -1
      frappe/website/router.py
  88. +2
    -1
      frappe/website/template.py
  89. +1
    -1
      frappe/website/utils.py
  90. +23
    -16
      frappe/website/website_generator.py

+ 16
- 0
frappe/__init__.py Voir le fichier

@@ -388,6 +388,22 @@ def has_permission(doctype, ptype="read", doc=None, user=None, verbose=False):
import frappe.permissions
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):
"""Returns True if `istable` property (indicating child Table) is set for given DocType."""
tables = cache().get_value("is_table")


+ 4
- 0
frappe/hooks.py Voir le fichier

@@ -29,6 +29,10 @@ web_include_css = [
"assets/css/frappe-web.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"]



+ 7
- 2
frappe/model/base_document.py Voir le fichier

@@ -432,8 +432,13 @@ class BaseDocument(object):

def get_formatted(self, fieldname, doc=None, currency=None):
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):
"""Returns true if fieldname is to be hidden for print.


+ 2
- 2
frappe/model/db_query.py Voir le fichier

@@ -23,7 +23,7 @@ class DatabaseQuery(object):

def execute(self, query=None, fields=None, filters=None, or_filters=None,
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):
if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user):
raise frappe.PermissionError, self.doctype
@@ -36,7 +36,7 @@ class DatabaseQuery(object):
self.group_by = group_by
self.order_by = order_by
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.debug = debug
self.as_list = as_list


+ 15
- 0
frappe/model/meta.py Voir le fichier

@@ -91,6 +91,7 @@ class Meta(Document):
if not self._fields:
for f in self.get("fields"):
self._fields[f.fieldname] = f

return self._fields.get(fieldname)

def get_label(self, fieldname):
@@ -306,3 +307,17 @@ def clear_cache(doctype=None):
frappe.cache().delete_keys(p + ":")

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"
)

+ 3
- 2
frappe/patches/v5_0/style_settings_to_website_theme.py Voir le fichier

@@ -1,8 +1,10 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint

def execute():
frappe.reload_doctype("Website Settings")
frappe.reload_doc("website", "doctype", "website_theme")
frappe.reload_doc("website", "website_theme", "standard")
migrate_style_settings()
@@ -20,8 +22,7 @@ def migrate_style_settings():
map_color_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.use_theme()


+ 30
- 30
frappe/public/css/avatar.css Voir le fichier

@@ -1,44 +1,44 @@
.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 {
width: 100%;
height: auto;
border-radius: 4px;
width: 100%;
height: auto;
border-radius: 4px;
}

.avatar-empty {
border: 1px dashed #d1d8dd;
border: 1px dashed #d1d8dd;
}

.avatar-small {
margin-right: 5px;
width: 24px;
height: 24px;
margin-right: 5px;
width: 24px;
height: 24px;
}

.avatar-medium {
margin-right: 5px;
width: 36px;
height: 36px;
margin-right: 5px;
width: 36px;
height: 36px;
}

.avatar-large {
margin-right: 10px;
width: 72px;
height: 72px;
margin-right: 10px;
width: 72px;
height: 72px;
}

.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%;
}

+ 145
- 0
frappe/public/css/common.css Voir le fichier

@@ -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;
}

+ 93
- 54
frappe/public/css/desk.css Voir le fichier

@@ -1,9 +1,24 @@
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 {
@@ -39,15 +54,6 @@ a.grey:hover,
border-bottom: 1px solid #212a33;
color: #212a33;
}
.text-color {
color: #36414c !important;
}
.text-muted {
color: #8d99a6 !important;
}
.text-extra-muted {
color: #d1d8dd !important;
}
a.text-muted,
a.text-extra-muted {
border-bottom: 1px solid transparent;
@@ -59,6 +65,84 @@ 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;
}
.nav-pills a,
.nav-pills a:hover {
border-bottom: none;
@@ -79,11 +163,6 @@ a.form-link {
.ui-autocomplete .link-option {
font-weight: normal;
}
.text-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scroll-to-top {
background-color: #fafbfc;
padding: 7px;
@@ -232,10 +311,6 @@ ul.linked-with-list li {
.form-group {
margin-bottom: 7px;
}
.bold,
.strong {
font-weight: bold;
}
.print-preview {
padding: 0px;
max-width: 8.3in;
@@ -305,10 +380,6 @@ ul.linked-with-list li {
#freeze.in {
opacity: 0.5;
}
kbd {
color: inherit;
background-color: #f0f4f7;
}
.msg-box {
padding: 30px 15px;
text-align: center;
@@ -335,41 +406,9 @@ kbd {
margin-top: 5px;
text-align: center;
}
.padding {
padding: 15px;
}
.set-filters .btn-xs {
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,
.footnote-area {
padding: 15px;


+ 1
- 0
frappe/public/css/form_grid.css Voir le fichier

@@ -71,6 +71,7 @@
.grid-row-open .form-in-grid {
opacity: 1;
height: auto;
overflow: visible;
}
.grid-form-heading {
padding: 10px 15px;


+ 8
- 3
frappe/public/css/mobile.css Voir le fichier

@@ -1,12 +1,17 @@
html,
html {
min-height: 100%;
}
body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
overflow-x: hidden;
/* Prevent scroll on narrow devices */
margin: 0px;
padding: 0px !important;
}
html,
body {
overflow-x: hidden;
/* Prevent scroll on narrow devices */
}
.offcanvas-main-section-overlay {
display: none;
cursor: pointer;


+ 8
- 3
frappe/public/css/offcanvas.css Voir le fichier

@@ -1,12 +1,17 @@
html,
html {
min-height: 100%;
}
body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
overflow-x: hidden;
/* Prevent scroll on narrow devices */
margin: 0px;
padding: 0px !important;
}
html,
body {
overflow-x: hidden;
/* Prevent scroll on narrow devices */
}
.offcanvas-main-section-overlay {
display: none;
cursor: pointer;


+ 8
- 3
frappe/public/css/sidebar.css Voir le fichier

@@ -1,12 +1,17 @@
html,
html {
min-height: 100%;
}
body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
overflow-x: hidden;
/* Prevent scroll on narrow devices */
margin: 0px;
padding: 0px !important;
}
html,
body {
overflow-x: hidden;
/* Prevent scroll on narrow devices */
}
.offcanvas-main-section-overlay {
display: none;
cursor: pointer;


+ 230
- 111
frappe/public/css/website.css Voir le fichier

@@ -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 {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
overflow-x: hidden;
/* Prevent scroll on narrow devices */
margin: 0px;
padding: 0px !important;
}
html,
body {
overflow-x: hidden;
/* Prevent scroll on narrow devices */
}
.offcanvas-main-section-overlay {
display: none;
cursor: pointer;
@@ -49,24 +199,85 @@ body {
.offcanvas .sidebar .dropdown-menu > li > a:active {
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 {
margin-bottom: 22px;
@@ -115,60 +326,6 @@ img {
padding: 20px 0px;
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 {
position: absolute;
top: 50%;
@@ -251,14 +408,8 @@ fieldset {
.page-container {
padding: 0px;
}
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 #d1d8dd;
}
.page-sidebar {
@@ -363,38 +514,6 @@ a.active {
.docs-attr-desc {
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 {
min-height: 400px;
}


+ 1
- 1
frappe/public/js/frappe/form/footer/assign_to.js Voir le fichier

@@ -51,7 +51,7 @@ frappe.ui.form.AssignTo = Class.extend({
<a class="close" data-owner="%(owner)s">&times;</a>\
<div class="text-ellipsis" style="width: 80%">\
<div class="avatar avatar-small">\
<img class="media-object" src="%(image)s">\
<img class="media-object" src="%(image)s" alt="%(fullname)s">\
</div>\
<span>%(fullname)s</span>\
</div>\


+ 1
- 1
frappe/public/js/frappe/form/formatters.js Voir le fichier

@@ -104,7 +104,7 @@ frappe.form.formatters = {
var html = "";
$.each(JSON.parse(value || "[]"), function(i, v) {
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;
},


+ 2
- 2
frappe/public/js/frappe/form/share.js Voir le fichier

@@ -22,8 +22,8 @@ frappe.ui.form.Share = Class.extend({
var user_info = frappe.user_info(shared[i])
$(repl('<span class="avatar avatar-small" title="'
+__("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
if(!me.frm.doc.__islocal) {


+ 32
- 3
frappe/public/js/frappe/misc/user.js Voir le fichier

@@ -6,10 +6,35 @@
frappe.user_info = function(uid) {
if(!uid)
uid = user;

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) {
@@ -17,9 +42,10 @@ frappe.avatar = function(user, css_class, title) {
if(!title) title = frappe.user_info(user).fullname;

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,
title: title,
abbr: frappe.user_info(user).abbr,
css_class: css_class || "avatar-small"
});
}
@@ -57,6 +83,9 @@ $.extend(frappe.user, {
image: function(uid) {
return frappe.user_info(uid).image;
},
abbr: function(uid) {
return frappe.user_info(uid).abbr;
},
has_role: function(rl) {
if(typeof rl=='string')
rl = [rl];


+ 3
- 2
frappe/public/js/frappe/ui/toolbar/awesome_bar.js Voir le fichier

@@ -212,11 +212,12 @@ frappe.search.verbs = [

try {
var val = eval(txt);
var formatted_value = $.format('{0} = {1}', [txt, "<b>"+val+"</b>"]);
frappe.search.options.push({
value: $.format('{0} = {1}', [txt, "<b>"+val+"</b>"]),
value: formatted_value,
match: val,
onclick: function(match) {
msgprint(match, "Result");
msgprint(formatted_value, "Result");
}
});
} catch(e) {


+ 1
- 1
frappe/public/js/frappe/ui/toolbar/navbar.html Voir le fichier

@@ -20,7 +20,7 @@
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"
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>
<b class="caret"></b></a>
<ul class="dropdown-menu" id="toolbar-user" role="menu">


+ 1
- 1
frappe/public/js/frappe/ui/toolbar/offcanvas_left_sidebar.html Voir le fichier

@@ -36,7 +36,7 @@
<div class="user-menu clearfix">
<div class="pull-left text-ellipsis" style="max-width: 75%;">
<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>
</a>
</div>


+ 51
- 0
frappe/public/less/avatar.less Voir le fichier

@@ -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%;
}

+ 156
- 0
frappe/public/less/common.less Voir le fichier

@@ -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
- 113
frappe/public/less/desk.less Voir le fichier

@@ -1,59 +1,6 @@
@import "variables.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 {
border-bottom: none;
@@ -78,12 +25,6 @@ a.form-link {
font-weight: normal;
}

.text-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.scroll-to-top {
background-color: @light-bg;
padding: 7px;
@@ -264,12 +205,6 @@ ul.linked-with-list li {
margin-bottom: 7px;
}


.bold,
.strong {
font-weight: bold;
}

.print-preview {
padding: 0px;
max-width: 8.3in;
@@ -340,11 +275,6 @@ ul.linked-with-list li {
opacity: 0.5;
}

kbd {
color: inherit;
background-color: @btn-bg;
}

.msg-box {
padding: 30px 15px;
text-align: center;
@@ -380,52 +310,10 @@ kbd {
text-align: center;
}

.padding {
padding: 15px;
}

.set-filters .btn-xs {
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,
.footnote-area {
padding: 15px;


+ 1
- 0
frappe/public/less/form_grid.less Voir le fichier

@@ -83,6 +83,7 @@
.grid-row-open .form-in-grid {
opacity: 1;
height: auto;
overflow: visible;
}

.grid-form-heading {


+ 0
- 8
frappe/public/less/navbar.less Voir le fichier

@@ -16,14 +16,6 @@
font-weight: bold;
}

// .navbar .breadcrumb-divider {
// margin-top: 10px;
// }

// .navbar .breadcrumb-divider i {
// color: #C0C9D2;
// }

.navbar-icon-home {
vertical-align: middle;
}


+ 8
- 2
frappe/public/less/offcanvas.less Voir le fichier

@@ -1,13 +1,19 @@
@import "variables.less";

html,
html {
min-height: 100%;
}

body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
overflow-x: hidden; /* Prevent scroll on narrow devices */
margin: 0px;
padding: 0px !important;
}

html,
body {
overflow-x: hidden; /* Prevent scroll on narrow devices */
}

.offcanvas-main-section-overlay {


+ 8
- 128
frappe/public/less/website.less Voir le fichier

@@ -1,24 +1,8 @@
@import "variables.less";
@import "common.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 {
margin-bottom: 22px;
@@ -78,65 +62,6 @@ img {
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 {
position: absolute;
top: 50%;
@@ -234,19 +159,7 @@ fieldset {
}

.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;
}

@@ -290,17 +203,17 @@ div[data-html-block="content"] {
/* post and post list */

.web-list-item {
padding: 15px 0px;
padding: 15px 0px;
border-bottom: 1px solid @border-color;
margin-right: -30px;
padding-right: 30px;

h3 {
margin: 0 0 5px 0;
margin: 0 0 5px 0;

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 {
min-height: 400px;
}


+ 5
- 5
frappe/templates/base.html Voir le fichier

@@ -50,9 +50,9 @@ Built on Frappe.io. Free and Open Source Framework for the Web. https://frappe.i
{%- endif %}
{%- endblock -%}

{%- block navbar -%}{% include "templates/includes/navbar.html" %}{%- endblock -%}
{%- block navbar -%}{% include "templates/includes/navbar/navbar.html" %}{%- endblock -%}
<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="col-sm-10 col-xs-12 page-content">
<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">
{%- if breadcrumbs is defined -%}{{ breadcrumbs }}{%- endif -%}
</div>
<div class="" data-html-block="content">
<div class="page-content-block" data-html-block="content">
{%- block content -%}{{ content or "" }}{%- endblock -%}
</div>
</div>
@@ -82,14 +82,14 @@ Built on Frappe.io. Free and Open Source Framework for the Web. https://frappe.i
</footer>
</div>
<div>
{%- block footer -%}{% include "templates/includes/footer.html" %}{%- endblock -%}
{%- block footer -%}{% include "templates/includes/footer/footer.html" %}{%- endblock -%}
</div>
</div>
<div class="modal-backdrop offcanvas-main-section-overlay"></div>
<div class="sidebar sidebar-right visible-xs">
{% block offcanvas_sidebar -%}
<div class="sidebar-navbar-items">
{% include "frappe/templates/includes/navbar_items.html" %}
{% include "templates/includes/navbar/navbar_items.html" %}
</div>
<div class="sidebar-page-sidebar" data-html-block="sidebar">
{%- if sidebar is defined -%}


+ 3
- 3
frappe/templates/generators/blog_post.html Voir le fichier

@@ -19,11 +19,11 @@
</article>
{% if blogger_info %}
<hr />
{% include "templates/includes/blogger.html" %}
{% include "templates/includes/blog/blogger.html" %}
{% endif %}
<hr>
<h3>Comments</h3>
{% include 'templates/includes/comments.html' %}
{% include 'templates/includes/comments/comments.html' %}
<script>
$(function() {
if(window.logged_in && getCookie("system_user")==="yes") {
@@ -36,4 +36,4 @@ $(function() {
</script>
{% endblock %}

{% block footer %}{% include 'templates/includes/blog_footer.html' %}{% endblock %}
{% block footer %}{% include 'templates/includes/blog/blog_footer.html' %}{% endblock %}

+ 1
- 1
frappe/templates/generators/web_form.html Voir le fichier

@@ -161,7 +161,7 @@
<div class="col-sm-offset-3 col-sm-9">
<hr>
<h3>{{ _("Comments") }}</h3>
{% include 'templates/includes/comments.html' %}
{% include 'templates/includes/comments/comments.html' %}
</div>
</div>
{%- endif %}


+ 1
- 1
frappe/templates/generators/web_page.html Voir le fichier

@@ -9,7 +9,7 @@
{% if enable_comments -%}
<hr>
<h3>Discuss</h3>
{% include 'templates/includes/comments.html' %}
{% include 'templates/includes/comments/comments.html' %}
{%- endif %}
</div>
<script>


+ 0
- 60
frappe/templates/includes/blog.js Voir le fichier

@@ -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);
}
});

frappe/templates/pages/blog.html → frappe/templates/includes/blog/blog.html Voir le fichier

@@ -7,11 +7,11 @@ window.category = null;
{% block content %}
<div class="blog-list-content">
{% if blog_introduction %}
<p>{{ blog_introduction }}</p>
<p class="blog-introduction">{{ blog_introduction }}</p>
{% endif %}
<h3 id="blot-subtitle" style="display:none;"></h3>
<h3 id="blot-subtitle" class="hide"></h3>
<div id="blog-list">
{{ posts }}
{% include "templates/includes/list/list.html" %}
</div>
<div class="blog-footer">
<p class="blog-message text-muted"></p>
@@ -21,9 +21,6 @@ window.category = null;
</div>
</div>
</div>
<script>
{% include "templates/includes/blog.js" %}
</script>
{% endblock %}

{% block footer %}{% include 'templates/includes/blog_footer.html' %}{% endblock %}
{% block footer %}{% include 'templates/includes/blog/blog_footer.html' %}{% endblock %}

frappe/templates/includes/blog_footer.html → frappe/templates/includes/blog/blog_footer.html Voir le fichier


+ 14
- 0
frappe/templates/includes/blog/blog_row.html Voir le fichier

@@ -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>

frappe/templates/includes/blogger.html → frappe/templates/includes/blog/blogger.html Voir le fichier


+ 0
- 16
frappe/templates/includes/blog_list.html Voir le fichier

@@ -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 -->

+ 6
- 2
frappe/templates/includes/breadcrumbs.html Voir le fichier

@@ -1,8 +1,12 @@
{% if parents and parents|length > 0 %}
<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>
{% endfor %}
<li class="active">{{ title or "" }}</li>
<li class="active">{{ title or "" }}</li> -->
#}
</ul>
{% endif %}

frappe/templates/includes/footer_extension.html → frappe/templates/includes/comments/__init__.py Voir le fichier


frappe/templates/includes/comment.html → frappe/templates/includes/comments/comment.html Voir le fichier


frappe/templates/includes/comments.html → frappe/templates/includes/comments/comments.html Voir le fichier

@@ -6,7 +6,7 @@

<div itemscope itemtype="http://schema.org/UserComments" id="comment-list">
{% for comment in comment_list %}
{% include "templates/includes/comment.html" %}
{% include "templates/includes/comments/comment.html" %}
{% endfor %}
</div>

@@ -75,7 +75,7 @@ frappe.ready(function() {
frappe.call({
btn: this,
type: "POST",
method: "frappe.templates.includes.comments.add_comment",
method: "frappe.templates.includes.comments.comments.add_comment",
args: args,
callback: function(r) {
if(r.exc) {

frappe/templates/includes/comments.py → frappe/templates/includes/comments/comments.py Voir le fichier


frappe/templates/includes/footer.html → frappe/templates/includes/footer/footer.html Voir le fichier

@@ -42,7 +42,7 @@
{# powered #}
<p class="text-right footer-powered">
{% block powered %}
{% include "templates/includes/footer_powered.html" %}
{% include "templates/includes/footer/footer_powered.html" %}
{% endblock %}
</p>
</div>
@@ -50,6 +50,6 @@
</div>
</section>
<section>
{% block extension %}{% include "templates/includes/footer_extension.html" %}{% endblock %}
{% block extension %}{% include "templates/includes/footer/footer_extension.html" %}{% endblock %}
</section>
</footer>

+ 0
- 0
frappe/templates/includes/footer/footer_extension.html Voir le fichier


frappe/templates/includes/footer_powered.html → frappe/templates/includes/footer/footer_powered.html Voir le fichier


+ 0
- 57
frappe/templates/includes/inline_post.html Voir le fichier

@@ -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
frappe/templates/includes/list/__init__.py Voir le fichier


+ 22
- 0
frappe/templates/includes/list/filters.html Voir le fichier

@@ -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">&times;</span> {{ _("clear") }} )</a></div>
</div>
{% endif %}
</div>

+ 31
- 0
frappe/templates/includes/list/list.css Voir le fichier

@@ -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;
}

+ 19
- 0
frappe/templates/includes/list/list.html Voir le fichier

@@ -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>

+ 31
- 0
frappe/templates/includes/list/list.js Voir le fichier

@@ -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");
}
};
})

+ 21
- 0
frappe/templates/includes/list/row_template.html Voir le fichier

@@ -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>

frappe/templates/includes/login.css → frappe/templates/includes/login/login.css Voir le fichier


frappe/templates/includes/login.js → frappe/templates/includes/login/login.js Voir le fichier


frappe/templates/includes/navbar.html → frappe/templates/includes/navbar/navbar.html Voir le fichier

@@ -11,7 +11,7 @@
</div>
<div class="hidden-xs">
{% block navbar_items %}
{% include "frappe/templates/includes/navbar_items.html" %}
{% include "templates/includes/navbar/navbar_items.html" %}
{% endblock %}
</div>
</div>

frappe/templates/includes/navbar_items.html → frappe/templates/includes/navbar/navbar_items.html Voir le fichier

@@ -2,7 +2,7 @@
<ul class="nav navbar-nav navbar-left">
{%- for page in top_bar_items -%}
{% if not page.parent_label and not page.right -%}
{% include "templates/includes/navbar_link.html" %}
{% include "templates/includes/navbar/navbar_link.html" %}
{%- endif -%}
{%- endfor %}
</ul>
@@ -10,16 +10,15 @@
<ul class="nav navbar-nav navbar-right">
{%- for page in top_bar_items -%}
{% if not page.parent_label and page.right -%}
{% include "templates/includes/navbar_link.html" %}
{% include "templates/includes/navbar/navbar_link.html" %}
{%- endif -%}
{%- endfor %}
<!-- post login tools -->
<li class="dropdown logged-in" id="website-post-login"
data-label="website-post-login" style="display: none">
<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>
<ul class="dropdown-menu" role="menu">
{%- for child in post_login -%}
@@ -29,9 +28,6 @@
{%- if child.url -%}
<a href="{{ child.url }}" {{ child.target or '' }}
rel="nofollow">
{%- if child.icon -%}
<i class="icon-fixed-width {{ child.icon }}"></i>
{%- endif -%}
{{ child.label }}
</a>
{%- endif -%}
@@ -40,5 +36,5 @@
</ul>
</li>
<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>

frappe/templates/includes/navbar_link.html → frappe/templates/includes/navbar/navbar_link.html Voir le fichier


+ 0
- 66
frappe/templates/includes/post_editor.html Voir le fichier

@@ -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">&times;</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>

+ 0
- 11
frappe/templates/includes/post_list.html Voir le fichier

@@ -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 %}

+ 0
- 8
frappe/templates/includes/sitemap_permission.html Voir le fichier

@@ -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>

+ 0
- 9
frappe/templates/includes/user_display.html Voir le fichier

@@ -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>

+ 36
- 7
frappe/templates/includes/website_theme/navbar.css Voir le fichier

@@ -4,6 +4,8 @@
background-image: none;
border: none;
border-bottom: 1px solid {{ get_shade(theme.top_bar_color, 10) }};
padding-top: 15px;
padding-bottom: 15px;
}

.navbar .navbar-text,
@@ -12,11 +14,9 @@
.navbar .nav > li > a {
color: {{ theme.top_bar_text_color }};
text-shadow: none;
padding-top: 25px;
padding-bottom: 25px;
}

{# links #}
/* navbar links */
.navbar .navbar-brand:hover,
.navbar .navbar-brand:focus,
.navbar .navbar-brand:active,
@@ -29,7 +29,11 @@
.navbar .navbar-link:active,
.navbar .nav > li > a:hover,
.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) }};
background-color: transparent;
-webkit-box-shadow: none;
@@ -54,7 +58,7 @@
border-radius: 0px;
}

{# navbar brand #}
/* navbar brand */
.navbar-brand {
padding-right: 30px;
max-width: 80%;
@@ -63,8 +67,8 @@
}

@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;
}

+ 0
- 64
frappe/templates/pages/blog.py Voir le fichier

@@ -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
- 1
frappe/templates/pages/complete_signup.html Voir le fichier

@@ -1,4 +1,4 @@
{% block style %}{% include "templates/includes/login.css" %}{% endblock %}
{% block style %}{% include "templates/includes/login/login.css" %}{% endblock %}

{% block content %}
<div class="login-content container" style="max-width: 800px;">


+ 5
- 80
frappe/templates/pages/list.html Voir le fichier

@@ -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">&times;</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 %}

+ 55
- 29
frappe/templates/pages/list.py Voir le fichier

@@ -2,26 +2,68 @@
# MIT License. See license.txt

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_sitemap = 1

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
module = load_doctype_module(context.doctype)
context.update(get_items(context.doctype, context.txt))

context.update(get(**frappe.local.form_dict))

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)
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)
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 meta.search_fields:
@@ -30,23 +72,7 @@ def get_items(doctype, txt, limit_start=0):
else:
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

+ 2
- 2
frappe/templates/pages/login.html Voir le fichier

@@ -1,4 +1,4 @@
{% block style %}{% include "templates/includes/login.css" %}{% endblock %}
{% block style %}{% include "templates/includes/login/login.css" %}{% endblock %}

{% block content %}
<!-- no-header -->
@@ -70,6 +70,6 @@
</div>
{% endblock %}

{% block script_lib %}{% include "templates/includes/login.js" %}{% endblock %}
{% block script_lib %}{% include "templates/includes/login/login.js" %}{% endblock %}

{% block sidebar %}{% endblock %}

+ 55
- 0
frappe/templates/pages/me.html Voir le fichier

@@ -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 %}

+ 23
- 0
frappe/templates/pages/me.py Voir le fichier

@@ -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

+ 3
- 1
frappe/templates/pages/print.py Voir le fichier

@@ -120,7 +120,9 @@ def validate_print_permission(doc):
return

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))

def get_letter_head(doc, no_letterhead):


+ 3
- 2
frappe/templates/pages/website_script.py Voir le fichier

@@ -13,8 +13,9 @@ def get_context(context):
script_context = { "javascript": frappe.db.get_value('Website Script', None, 'javascript') }

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:
script_context["google_analytics_id"] = frappe.db.get_value("Website Settings", "Website Settings",


+ 1
- 1
frappe/templates/pages/website_theme.css Voir le fichier

@@ -38,7 +38,7 @@ a {
a:hover,
a:focus,
a:active {
color: {{ get_shade(theme.link_color, 5) }};
color: {{ get_shade(theme.link_color, 25) }};
}

{# headings #}


+ 2
- 2
frappe/templates/pages/writers.html Voir le fichier

@@ -6,10 +6,10 @@
<p>{{ writers_introduction }}</p>
{% endif %}
{% for blogger_info in bloggers %}
{% include "templates/includes/blogger.html" %}
{% include "templates/includes/blog/blogger.html" %}
{% if not loop.last %}<hr>{% endif %}
{% endfor %}
</div>
{% endblock %}

{% block footer %}{% include "templates/includes/blog_footer.html" %}{% endblock %}
{% block footer %}{% include "templates/includes/blog/blog_footer.html" %}{% endblock %}

+ 17
- 12
frappe/utils/data.py Voir le fichier

@@ -164,6 +164,12 @@ def get_datetime_str(datetime_obj):

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):
"""
Convers the given string date to :data:`user_format`
@@ -176,21 +182,20 @@ def formatdate(string_date=None, format_string=None):
* dd/mm/yyyy
"""
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):
"""returns date as 1 January 2012"""


+ 5
- 2
frappe/utils/formatters.py Voir le fichier

@@ -3,7 +3,7 @@

from __future__ import unicode_literals
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
import re

@@ -11,10 +11,13 @@ def format_value(value, df, doc=None, currency=None):
# Convert dict to object if necessary
if (isinstance(df, dict)):
df = frappe._dict(df)
if df.get("fieldtype")=="Date":
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()):
return fmt_money(value, precision=get_field_precision(df, doc),
currency=currency if currency else (get_field_currency(df, doc) if doc else None))


+ 7
- 2
frappe/utils/user.py Voir le fichier

@@ -4,6 +4,7 @@
from __future__ import unicode_literals

import frappe, json
from frappe import _dict

class User:
"""
@@ -30,6 +31,7 @@ class User:
self.can_set_user_permissions = []
self.allow_modules = []
self.in_create = []
self.doc = frappe.get_doc("User", self.name)

def get_roles(self):
"""get list of roles"""
@@ -167,10 +169,10 @@ def get_user_fullname(user):
def get_fullname_and_avatar(user):
first_name, last_name, avatar = frappe.db.get_value("User",
user, ["first_name", "last_name", "user_image"])
return {
return _dict({
"fullname": " ".join(filter(None, [first_name, last_name])),
"avatar": avatar
}
})

def get_system_managers(only_name=False):
"""returns all system manager's user details"""
@@ -234,3 +236,6 @@ def get_roles(user=None, with_standard=True):
def get_enabled_system_users():
return frappe.db.sql("""select * from tabUser where
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"

+ 1
- 0
frappe/website/context.py Voir le fichier

@@ -46,6 +46,7 @@ def build_context(context):
# provide doc
if context.doc:
context.update(context.doc.as_dict())
context.update(context.doc.website)
if hasattr(context.doc, "get_context"):
ret = context.doc.get_context(context)
if ret:


+ 0
- 8
frappe/website/doctype/blog_category/blog_category.py Voir le fichier

@@ -8,9 +8,6 @@ from frappe.website.render import clear_cache
from frappe.templates.pages.blog import get_context

class BlogCategory(WebsiteGenerator):
page_title_field = "title"
template = "templates/generators/blog_category.html"
no_cache = True
def autoname(self):
# to override autoname of WebsiteGenerator
self.name = self.category_name
@@ -22,8 +19,3 @@ class BlogCategory(WebsiteGenerator):
def validate(self):
self.parent_website_route = "blog"
super(BlogCategory, self).validate()

def get_context(self, context):
"""Build context from `frappe.templates.pages.blog`"""
context.category = self.name
get_context(context)

+ 77
- 7
frappe/website/doctype/blog_post/blog_post.py Voir le fichier

@@ -4,20 +4,21 @@
from __future__ import unicode_literals

import frappe, re
from frappe import _
from frappe.website.website_generator import WebsiteGenerator
from frappe.website.render import clear_cache
from frappe.utils import today, cint, global_date_format, get_fullname
from frappe.website.utils import find_first_image, get_comment_list
from frappe.templates.pages.blog import get_children

class BlogPost(WebsiteGenerator):
condition_field = "published"
template = "templates/generators/blog_post.html"
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):
return self.title
@@ -74,6 +75,24 @@ class BlogPost(WebsiteGenerator):

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():
for blog in frappe.db.sql_list("""select page_name from
`tabBlog Post` where ifnull(published,0)=1"""):
@@ -81,3 +100,54 @@ def clear_blog_cache():

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

+ 6
- 4
frappe/website/doctype/web_form/web_form.py Voir le fichier

@@ -8,10 +8,12 @@ from frappe import _
from frappe.utils.file_manager import save_file, remove_file_by_url

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):
context.params = frappe.form_dict


+ 6
- 4
frappe/website/doctype/web_page/web_page.py Voir le fichier

@@ -14,10 +14,12 @@ from jinja2.exceptions import TemplateSyntaxError

class WebPage(WebsiteGenerator):
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):
return self.title


+ 5
- 4
frappe/website/doctype/website_settings/website_settings.py Voir le fichier

@@ -85,8 +85,9 @@ def get_website_settings():
where parent='Website Settings' and parentfield='footer_items'
order by idx asc""", as_dict=1),
"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(""))

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 []



+ 2
- 0
frappe/website/doctype/website_theme/website_theme.py Voir le fichier

@@ -64,6 +64,8 @@ def add_website_theme(context):
bootstrap = frappe.get_hooks("bootstrap")[0]
website_theme = get_active_theme()
if website_theme:
context.website_theme = website_theme

if website_theme.bootstrap:
bootstrap = website_theme.bootstrap



+ 2
- 3
frappe/website/js/website.js Voir le fichier

@@ -192,7 +192,7 @@ $.extend(frappe, {
$(".btn-login-area").toggle(false);
$(".logged-in").toggle(true);
$(".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() {
@@ -577,8 +577,7 @@ $(document).ready(function() {

// switch to app link
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();


+ 23
- 1
frappe/website/render.py Voir le fichier

@@ -7,6 +7,7 @@ from frappe import _
from frappe.utils import cstr
import mimetypes, json
from werkzeug.wrappers import Response
from werkzeug.routing import Map, Rule, NotFound

from frappe.website.context import get_context
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):
"""render html page"""
path = resolve_path(path.strip("/ "))
frappe.local.path = path

try:
data = render_page(path)
@@ -158,6 +158,28 @@ def resolve_path(path):
if path == "index":
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

def set_content_type(response, data, path):


+ 1
- 1
frappe/website/router.py Voir le fichier

@@ -28,7 +28,7 @@ def build_route(path):

context.doctype = context.ref_doctype
context.title = context.page_title
context.pathname = path
context.pathname = frappe.local.path

return context



+ 2
- 1
frappe/website/template.py Voir le fichier

@@ -26,7 +26,8 @@ def render_blocks(context):

template = frappe.get_template(template_path)
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"])



+ 1
- 1
frappe/website/utils.py Voir le fichier

@@ -26,7 +26,7 @@ def find_first_image(html):
return None

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):
return frappe.db.sql("""select


+ 23
- 16
frappe/website/website_generator.py Voir le fichier

@@ -12,7 +12,10 @@ from frappe.modules import get_module_name
from frappe.website.router import get_page_route

class WebsiteGenerator(Document):
page_title_field = "name"
website = frappe._dict(
page_title_field = "name"
)

def autoname(self):
if self.meta.autoname != "hash":
self.name = self.get_page_name()
@@ -77,15 +80,16 @@ class WebsiteGenerator(Document):
clear_cache(self.get_route())

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:
return True

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:
self.parent_website_route = frappe.get_doc(field.options,
parent).get_route()
@@ -121,11 +125,13 @@ class WebsiteGenerator(Document):
"docname": self.name,
"page_name": self.get_page_name(),
"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)

return route
@@ -147,7 +153,7 @@ class WebsiteGenerator(Document):
parents = []
me = self
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

# if no parent and not home page, then parent is home page
@@ -165,7 +171,7 @@ class WebsiteGenerator(Document):

if parent_doc:
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:
parent_info = frappe._dict(name=self.parent_website_route,
title=self.parent_website_route.replace("_", " ").title())
@@ -188,8 +194,9 @@ class WebsiteGenerator(Document):
return parents

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):
children = []
@@ -214,9 +221,9 @@ class WebsiteGenerator(Document):
where ifnull(parent_website_route,'')=%s
order by {order_by}""".format(
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:
c.name = make_route(c)


Chargement…
Annuler
Enregistrer