@@ -391,6 +391,9 @@ def get_module_path(module, *joins): | |||||
def get_app_path(app_name, *joins): | def get_app_path(app_name, *joins): | ||||
return get_pymodule_path(app_name, *joins) | return get_pymodule_path(app_name, *joins) | ||||
def get_site_path(*joins): | |||||
return os.path.join(local.site_path, *joins) | |||||
def get_pymodule_path(modulename, *joins): | def get_pymodule_path(modulename, *joins): | ||||
joins = [scrub(part) for part in joins] | joins = [scrub(part) for part in joins] | ||||
@@ -512,6 +515,10 @@ def get_application_home_page(user='Guest'): | |||||
else: | else: | ||||
return conn.get_value("Control Panel", None, "home_page") | return conn.get_value("Control Panel", None, "home_page") | ||||
def import_doclist(path, ignore_links=False, ignore_insert=False): | |||||
from frappe.core.page.data_import_tool import data_import_tool | |||||
data_import_tool.import_doclist(path, ignore_links=ignore_links, ignore_insert=ignore_insert) | |||||
def copy_doclist(in_doclist): | def copy_doclist(in_doclist): | ||||
new_doclist = [] | new_doclist = [] | ||||
parent_doc = None | parent_doc = None | ||||
@@ -181,6 +181,7 @@ def setup_utilities(parser): | |||||
parser.add_argument("--python", action="store_true", help="get python shell for a site") | parser.add_argument("--python", action="store_true", help="get python shell for a site") | ||||
parser.add_argument("--flush_memcache", action="store_true", help="flush memcached") | parser.add_argument("--flush_memcache", action="store_true", help="flush memcached") | ||||
parser.add_argument("--ipython", action="store_true", help="get ipython shell for a site") | parser.add_argument("--ipython", action="store_true", help="get ipython shell for a site") | ||||
parser.add_argument("--execute", help="execute a function", nargs=1, metavar="FUNCTION") | |||||
parser.add_argument("--get_site_status", action="store_true", help="Get site details") | parser.add_argument("--get_site_status", action="store_true", help="Get site details") | ||||
parser.add_argument("--update_site_config", nargs=1, | parser.add_argument("--update_site_config", nargs=1, | ||||
metavar="site-CONFIG-JSON", | metavar="site-CONFIG-JSON", | ||||
@@ -465,6 +466,13 @@ def reset_perms(): | |||||
frappe.reset_perms(d) | frappe.reset_perms(d) | ||||
frappe.destroy() | frappe.destroy() | ||||
@cmd | |||||
def execute(method): | |||||
frappe.connect() | |||||
frappe.get_attr(method)() | |||||
frappe.conn.commit() | |||||
frappe.destroy() | |||||
# scheduler | # scheduler | ||||
@cmd | @cmd | ||||
def run_scheduler(): | def run_scheduler(): | ||||
@@ -489,11 +489,12 @@ def delete_child_rows(rows, doctype): | |||||
for p in list(set([r[1] for r in rows])): | for p in list(set([r[1] for r in rows])): | ||||
frappe.conn.sql("""delete from `tab%s` where parent=%s""" % (doctype, '%s'), p) | frappe.conn.sql("""delete from `tab%s` where parent=%s""" % (doctype, '%s'), p) | ||||
import csv | |||||
def import_file_by_path(path, ignore_links=False, overwrite=False): | def import_file_by_path(path, ignore_links=False, overwrite=False): | ||||
from frappe.utils.datautils import read_csv_content | from frappe.utils.datautils import read_csv_content | ||||
print "Importing " + path | print "Importing " + path | ||||
with open(path, "r") as infile: | with open(path, "r") as infile: | ||||
upload(rows = read_csv_content(infile.read()), ignore_links=ignore_links, overwrite=overwrite) | |||||
upload(rows = read_csv_content(infile), ignore_links=ignore_links, overwrite=overwrite) | |||||
def export_csv(doctype, path): | def export_csv(doctype, path): | ||||
with open(path, "w") as csvfile: | with open(path, "w") as csvfile: | ||||
@@ -513,18 +514,34 @@ def export_json(doctype, name, path): | |||||
d["__islocal"] = 1 | d["__islocal"] = 1 | ||||
outfile.write(json.dumps(doclist, default=json_handler, indent=1, sort_keys=True)) | outfile.write(json.dumps(doclist, default=json_handler, indent=1, sort_keys=True)) | ||||
def import_doclist(path, overwrite=False): | |||||
def import_doclist(path, overwrite=False, ignore_links=False, ignore_insert=False): | |||||
import os | import os | ||||
if os.path.isdir(path): | if os.path.isdir(path): | ||||
files = [os.path.join(path, f) for f in os.listdir(path)] | files = [os.path.join(path, f) for f in os.listdir(path)] | ||||
else: | else: | ||||
files = [path] | files = [path] | ||||
def _import_doclist(d): | |||||
b = frappe.bean(d) | |||||
b.ignore_links = ignore_links | |||||
try: | |||||
b.insert_or_update() | |||||
except NameError: | |||||
if ignore_insert: | |||||
pass | |||||
else: | |||||
raise | |||||
print "Imported: " + b.doc.doctype + " / " + b.doc.name | |||||
for f in files: | for f in files: | ||||
if f.endswith(".json"): | if f.endswith(".json"): | ||||
with open(f, "r") as infile: | with open(f, "r") as infile: | ||||
b = frappe.bean(json.loads(infile.read())).insert_or_update() | |||||
print "Imported: " + b.doc.doctype + " / " + b.doc.name | |||||
data = json.loads(infile.read()) | |||||
if isinstance(data, list): | |||||
for doc in data: | |||||
_import_doclist(doc) | |||||
else: | |||||
_import_doclist(data) | |||||
frappe.conn.commit() | frappe.conn.commit() | ||||
if f.endswith(".csv"): | if f.endswith(".csv"): | ||||
import_file_by_path(f, ignore_links=True, overwrite=overwrite) | import_file_by_path(f, ignore_links=True, overwrite=overwrite) |
@@ -59,6 +59,8 @@ class Document: | |||||
if isinstance(doctype, dict): | if isinstance(doctype, dict): | ||||
fielddata = doctype | fielddata = doctype | ||||
doctype = None | doctype = None | ||||
if doctype and isinstance(name, dict): | |||||
name = frappe.conn.get_value(doctype, name, "name") or None | |||||
if fielddata: | if fielddata: | ||||
self.fields = frappe._dict(fielddata) | self.fields = frappe._dict(fielddata) | ||||
@@ -370,6 +370,9 @@ class DocTypeDocList(frappe.model.doclist.DocList): | |||||
fields = self.get(filters) | fields = self.get(filters) | ||||
if fields: | if fields: | ||||
return fields[0] | return fields[0] | ||||
def has_field(self, fieldname): | |||||
return fieldname in self.get_fieldnames() | |||||
def get_fieldnames(self, filters=None): | def get_fieldnames(self, filters=None): | ||||
if not filters: filters = {} | if not filters: filters = {} | ||||
@@ -31,7 +31,7 @@ frappe.avatar = function(user, large, title) { | |||||
} | } | ||||
frappe.ui.set_user_background = function(src) { | frappe.ui.set_user_background = function(src) { | ||||
if(!src) src = "assets/frappe/images/ui/field.jpg"; | |||||
if(!src) src = "assets/frappe/images/ui/background-4-1.jpg"; | |||||
frappe.dom.set_style(repl('#page-desktop { \ | frappe.dom.set_style(repl('#page-desktop { \ | ||||
position: fixed;\ | position: fixed;\ | ||||
left: 0px; min-width: 100%; height: 100%; overflow: auto;\ | left: 0px; min-width: 100%; height: 100%; overflow: auto;\ | ||||
@@ -13,6 +13,7 @@ $.extend(frappe.model, { | |||||
std_fields: [ | std_fields: [ | ||||
{fieldname:'name', fieldtype:'Link', label:'ID'}, | {fieldname:'name', fieldtype:'Link', label:'ID'}, | ||||
{fieldname:'owner', fieldtype:'Data', label:'Created By'}, | {fieldname:'owner', fieldtype:'Data', label:'Created By'}, | ||||
{fieldname:'idx', fieldtype:'Int', label:'Index'}, | |||||
{fieldname:'creation', fieldtype:'Date', label:'Created On'}, | {fieldname:'creation', fieldtype:'Date', label:'Created On'}, | ||||
{fieldname:'modified', fieldtype:'Date', label:'Last Updated On'}, | {fieldname:'modified', fieldtype:'Date', label:'Last Updated On'}, | ||||
{fieldname:'modified_by', fieldtype:'Data', label:'Last Updated By'}, | {fieldname:'modified_by', fieldtype:'Data', label:'Last Updated By'}, | ||||
@@ -23,7 +24,6 @@ $.extend(frappe.model, { | |||||
std_fields_table: [ | std_fields_table: [ | ||||
{fieldname:'parent', fieldtype:'Data', label:'Parent'}, | {fieldname:'parent', fieldtype:'Data', label:'Parent'}, | ||||
{fieldname:'idx', fieldtype:'Int', label:'Row No.'}, | |||||
], | ], | ||||
new_names: {}, | new_names: {}, | ||||
@@ -365,7 +365,7 @@ frappe.ui.FieldSelect = Class.extend({ | |||||
if(d.fieldname=="name") opts.options = me.doctype; | if(d.fieldname=="name") opts.options = me.doctype; | ||||
return $.extend(copy_dict(d), opts); | return $.extend(copy_dict(d), opts); | ||||
}); | }); | ||||
// add parenttype column | // add parenttype column | ||||
var doctype_obj = locals['DocType'][me.doctype]; | var doctype_obj = locals['DocType'][me.doctype]; | ||||
if(doctype_obj && cint(doctype_obj.istable)) { | if(doctype_obj && cint(doctype_obj.istable)) { | ||||
@@ -13,10 +13,14 @@ frappe.ui.Tree = Class.extend({ | |||||
tree: this, | tree: this, | ||||
parent: this.$w, | parent: this.$w, | ||||
label: this.label, | label: this.label, | ||||
parent_label: null, | |||||
expandable: true | expandable: true | ||||
}); | }); | ||||
this.set_style(); | this.set_style(); | ||||
}, | }, | ||||
get_selected_node: function() { | |||||
return this.$w.find('.tree-link.selected').data('node'); | |||||
}, | |||||
set_style: function() { | set_style: function() { | ||||
frappe.dom.set_style("\ | frappe.dom.set_style("\ | ||||
.tree li { list-style: none; }\ | .tree li { list-style: none; }\ | ||||
@@ -33,6 +37,8 @@ frappe.ui.TreeNode = Class.extend({ | |||||
this.loaded = false; | this.loaded = false; | ||||
this.expanded = false; | this.expanded = false; | ||||
this.tree.nodes[this.label] = this; | this.tree.nodes[this.label] = this; | ||||
if(this.parent_label) | |||||
this.parent_node = this.tree.nodes[this.parent_label]; | |||||
this.$a = $('<span class="tree-link">') | this.$a = $('<span class="tree-link">') | ||||
.click(function() { | .click(function() { | ||||
if(me.expandable && me.tree.method && !me.loaded) { | if(me.expandable && me.tree.method && !me.loaded) { | ||||
@@ -44,6 +50,7 @@ frappe.ui.TreeNode = Class.extend({ | |||||
}) | }) | ||||
.bind('reload', function() { me.reload(); }) | .bind('reload', function() { me.reload(); }) | ||||
.data('label', this.label) | .data('label', this.label) | ||||
.data('node', this) | |||||
.appendTo(this.parent); | .appendTo(this.parent); | ||||
// label with icon | // label with icon | ||||
@@ -94,6 +101,7 @@ frappe.ui.TreeNode = Class.extend({ | |||||
return new frappe.ui.TreeNode({ | return new frappe.ui.TreeNode({ | ||||
tree:this.tree, | tree:this.tree, | ||||
parent: $('<li>').appendTo(this.$ul), | parent: $('<li>').appendTo(this.$ul), | ||||
parent_label: this.label, | |||||
label: data.value, | label: data.value, | ||||
expandable: data.expandable, | expandable: data.expandable, | ||||
data: data | data: data | ||||
@@ -208,9 +208,9 @@ frappe.views.ReportView = frappe.ui.Listing.extend({ | |||||
var docfield = frappe.meta.docfield_map[c[1] || me.doctype][c[0]]; | var docfield = frappe.meta.docfield_map[c[1] || me.doctype][c[0]]; | ||||
if(!docfield) { | if(!docfield) { | ||||
var docfield = frappe.model.get_std_field(c[0]); | var docfield = frappe.model.get_std_field(c[0]); | ||||
docfield.parent = me.doctype; | |||||
if(c[0]=="name") { | if(c[0]=="name") { | ||||
docfield.options = me.doctype; | docfield.options = me.doctype; | ||||
docfield.parent = me.doctype; | |||||
} | } | ||||
} | } | ||||
coldef = { | coldef = { | ||||
@@ -293,6 +293,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({ | |||||
if(e.target.className === "slick-resizable-handle") | if(e.target.className === "slick-resizable-handle") | ||||
return; | return; | ||||
var df = args.column.docfield, | var df = args.column.docfield, | ||||
sort_by = df.parent + "." + df.fieldname; | sort_by = df.parent + "." + df.fieldname; | ||||
@@ -1,14 +1,3 @@ | |||||
<div class="blog-footer"> | <div class="blog-footer"> | ||||
<p> | |||||
{% if categories %} | |||||
<h5>Explore posts by categories</h5> | |||||
<ul class="breadcrumb" style="background-color: transparent; padding-left: 20px;"> | |||||
{% for category in frappe.conn.sql_list("select name from `tabBlog Category` order by name") %} | |||||
<li><a href="/blog?category={{ category }}">{{ category }}</a> | |||||
{% endfor %} | |||||
</ul> | |||||
<br><br> | |||||
{% endif %} | |||||
<p>Show posts by <a href="/blog">everyone</a>. Meet the <a href="/writers">writers</a> of this blog</p> | |||||
</p> | |||||
<p>Show posts by <a href="/blog">everyone</a>. Meet the <a href="/writers">writers</a> of this blog</p> | |||||
</div> | </div> |
@@ -1,5 +1,9 @@ | |||||
{% block title %}{{ blog_title or "Blog" }}{% endblock %} | {% block title %}{{ blog_title or "Blog" }}{% endblock %} | ||||
{% block script %} | |||||
window.category = null; | |||||
{% endblock %} | |||||
{% block content %} | {% block content %} | ||||
<div class="blog-list-content"> | <div class="blog-list-content"> | ||||
{% if blog_introduction %} | {% if blog_introduction %} | ||||
@@ -11,7 +11,7 @@ from frappe.utils import encode, cstr, cint, flt | |||||
def read_csv_content_from_uploaded_file(ignore_encoding=False): | def read_csv_content_from_uploaded_file(ignore_encoding=False): | ||||
if getattr(frappe, "uploaded_file", None): | if getattr(frappe, "uploaded_file", None): | ||||
with open(frappe.uploaded_file, "r") as upfile: | with open(frappe.uploaded_file, "r") as upfile: | ||||
fcontent = upfile.read() | |||||
fcontent = upfile | |||||
else: | else: | ||||
from frappe.utils.file_manager import get_uploaded_content | from frappe.utils.file_manager import get_uploaded_content | ||||
fname, fcontent = get_uploaded_content() | fname, fcontent = get_uploaded_content() | ||||
@@ -35,21 +35,24 @@ def read_csv_content_from_attached_file(doc): | |||||
def read_csv_content(fcontent, ignore_encoding=False): | def read_csv_content(fcontent, ignore_encoding=False): | ||||
rows = [] | rows = [] | ||||
decoded = False | |||||
for encoding in ["utf-8", "windows-1250", "windows-1252"]: | |||||
try: | |||||
fcontent = unicode(fcontent, encoding) | |||||
decoded = True | |||||
break | |||||
except UnicodeDecodeError, e: | |||||
continue | |||||
if not decoded: | |||||
frappe.msgprint(frappe._("Unknown file encoding. Tried utf-8, windows-1250, windows-1252."), | |||||
raise_exception=True) | |||||
if isinstance(fcontent, basestring): | |||||
decoded = False | |||||
for encoding in ["utf-8", "windows-1250", "windows-1252"]: | |||||
try: | |||||
fcontent = unicode(fcontent, encoding) | |||||
decoded = True | |||||
break | |||||
except UnicodeDecodeError, e: | |||||
continue | |||||
if not decoded: | |||||
frappe.msgprint(frappe._("Unknown file encoding. Tried utf-8, windows-1250, windows-1252."), | |||||
raise_exception=True) | |||||
fcontent = fcontent.encode("utf-8").splitlines(True) | |||||
try: | try: | ||||
reader = csv.reader(fcontent.encode("utf-8").splitlines(True)) | |||||
reader = csv.reader(fcontent) | |||||
# decode everything | # decode everything | ||||
rows = [[unicode(val, "utf-8").strip() for val in row] for row in reader] | rows = [[unicode(val, "utf-8").strip() for val in row] for row in reader] | ||||
return rows | return rows | ||||
@@ -56,7 +56,7 @@ def parse_date(date): | |||||
def get_user_date_format(): | def get_user_date_format(): | ||||
if getattr(frappe.local, "user_date_format", None) is None: | if getattr(frappe.local, "user_date_format", None) is None: | ||||
frappe.local.user_date_format = frappe.defaults.get_global_default("date_format") | |||||
frappe.local.user_date_format = frappe.defaults.get_global_default("date_format") or "yyyy-mm-dd" | |||||
return frappe.local.user_date_format | return frappe.local.user_date_format | ||||
@@ -273,6 +273,7 @@ body { | |||||
.page-footer { | .page-footer { | ||||
margin: 20px 0px 0px; | margin: 20px 0px 0px; | ||||
padding: 15px 0px; | |||||
border-top: 1px solid #eee; | border-top: 1px solid #eee; | ||||
} | } | ||||
@@ -3,7 +3,7 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe | |||||
import frappe, re | |||||
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 | ||||
@@ -21,6 +21,10 @@ class DocType(WebsiteGenerator): | |||||
return frappe.conn.get_value("Website Sitemap", {"ref_doctype": "Blog Category", "docname": self.doc.blog_category}) | return frappe.conn.get_value("Website Sitemap", {"ref_doctype": "Blog Category", "docname": self.doc.blog_category}) | ||||
def validate(self): | def validate(self): | ||||
if not self.doc.blog_intro: | |||||
self.doc.blog_intro = self.doc.content[:140] | |||||
re.sub("\<[^>]*\>", "", self.doc.blog_intro) | |||||
if self.doc.blog_intro: | if self.doc.blog_intro: | ||||
self.doc.blog_intro = self.doc.blog_intro[:140] | self.doc.blog_intro = self.doc.blog_intro[:140] | ||||
@@ -2,7 +2,7 @@ | |||||
{ | { | ||||
"creation": "2013-03-28 10:35:30", | "creation": "2013-03-28 10:35:30", | ||||
"docstatus": 0, | "docstatus": 0, | ||||
"modified": "2014-01-20 17:48:25", | |||||
"modified": "2014-02-17 13:00:42", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"owner": "Administrator" | "owner": "Administrator" | ||||
}, | }, | ||||
@@ -25,6 +25,7 @@ | |||||
}, | }, | ||||
{ | { | ||||
"cancel": 0, | "cancel": 0, | ||||
"delete": 0, | |||||
"doctype": "DocPerm", | "doctype": "DocPerm", | ||||
"email": 1, | "email": 1, | ||||
"name": "__common__", | "name": "__common__", | ||||
@@ -94,7 +95,7 @@ | |||||
"fieldtype": "Small Text", | "fieldtype": "Small Text", | ||||
"in_list_view": 1, | "in_list_view": 1, | ||||
"label": "Blog Intro", | "label": "Blog Intro", | ||||
"reqd": 1 | |||||
"reqd": 0 | |||||
}, | }, | ||||
{ | { | ||||
"doctype": "DocField", | "doctype": "DocField", | ||||
@@ -120,7 +121,6 @@ | |||||
}, | }, | ||||
{ | { | ||||
"create": 1, | "create": 1, | ||||
"delete": 1, | |||||
"doctype": "DocPerm", | "doctype": "DocPerm", | ||||
"restrict": 1, | "restrict": 1, | ||||
"role": "Website Manager", | "role": "Website Manager", | ||||
@@ -128,13 +128,11 @@ | |||||
}, | }, | ||||
{ | { | ||||
"create": 1, | "create": 1, | ||||
"delete": 0, | |||||
"doctype": "DocPerm", | "doctype": "DocPerm", | ||||
"role": "Blogger", | "role": "Blogger", | ||||
"write": 1 | "write": 1 | ||||
}, | }, | ||||
{ | { | ||||
"delete": 0, | |||||
"doctype": "DocPerm", | "doctype": "DocPerm", | ||||
"role": "Guest", | "role": "Guest", | ||||
"write": 0 | "write": 0 | ||||
@@ -59,9 +59,11 @@ def _sync_statics(): | |||||
if str(os.path.getmtime(fpath))!=sitemap.doc.static_file_timestamp \ | if str(os.path.getmtime(fpath))!=sitemap.doc.static_file_timestamp \ | ||||
or cint(sitemap.doc.idx) != cint(priority): | or cint(sitemap.doc.idx) != cint(priority): | ||||
page = frappe.bean("Web Page", sitemap.doc.docname) | page = frappe.bean("Web Page", sitemap.doc.docname) | ||||
title, content = get_static_content(fpath) | title, content = get_static_content(fpath) | ||||
page.doc.main_section = content | page.doc.main_section = content | ||||
page.doc.idx = priority | |||||
if not title: | if not title: | ||||
title = page_name.replace("-", " ").replace("_", " ").title() | title = page_name.replace("-", " ").replace("_", " ").title() | ||||
page.doc.title = title | page.doc.title = title | ||||
@@ -69,7 +71,6 @@ def _sync_statics(): | |||||
sitemap = frappe.bean("Website Sitemap", url) | sitemap = frappe.bean("Website Sitemap", url) | ||||
sitemap.doc.static_file_timestamp = os.path.getmtime(fpath) | sitemap.doc.static_file_timestamp = os.path.getmtime(fpath) | ||||
sitemap.doc.idx = priority | |||||
sitemap.save() | sitemap.save() | ||||
synced.append(url) | synced.append(url) | ||||
@@ -36,8 +36,6 @@ class DocType(DocTypeNestedSet): | |||||
self.doc.idx = int(frappe.conn.sql("""select max(idx) from `tabWebsite Sitemap` | self.doc.idx = int(frappe.conn.sql("""select max(idx) from `tabWebsite Sitemap` | ||||
where parent_website_sitemap=%s and name!=%s""", (self.doc.parent_website_sitemap, | where parent_website_sitemap=%s and name!=%s""", (self.doc.parent_website_sitemap, | ||||
self.doc.name))[0][0] or 0) + 1 | self.doc.name))[0][0] or 0) + 1 | ||||
else: | else: | ||||
if self.doc.idx != 0: | if self.doc.idx != 0: | ||||
if not frappe.conn.get_value("Website Sitemap", { | if not frappe.conn.get_value("Website Sitemap", { | ||||
@@ -0,0 +1,188 @@ | |||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
// MIT License. See license.txt" | |||||
frappe.pages['sitemap-browser'].onload = function(wrapper) { | |||||
frappe.ui.make_app_page({ | |||||
parent: wrapper, | |||||
title: 'Sitemap Browser', | |||||
}); | |||||
wrapper.appframe.add_module_icon("Website") | |||||
wrapper.appframe.set_title_right('Refresh', function() { | |||||
wrapper.make_tree(); | |||||
}); | |||||
$(wrapper) | |||||
.find(".layout-side-section") | |||||
.html('<div class="text-muted">'+ | |||||
frappe._('Click on a link to get options to expand get options ') + | |||||
frappe._('Add') + ' / ' + frappe._('Edit') + ' / '+ frappe._('Remove') + '.</div>') | |||||
frappe.website.sitemap = new frappe.website.SitemapBrowser( | |||||
$(wrapper) | |||||
.find(".layout-main-section") | |||||
.css({ | |||||
"min-height": "300px", | |||||
"padding-bottom": "25px" | |||||
})); | |||||
} | |||||
frappe.provide("frappe.website"); | |||||
frappe.website.SitemapBrowser = Class.extend({ | |||||
init: function(parent) { | |||||
$(parent).empty(); | |||||
var me = this; | |||||
this.tree = new frappe.ui.Tree({ | |||||
parent: $(parent), | |||||
label: "Sitemap", | |||||
method: 'frappe.website.page.sitemap_browser.sitemap_browser.get_children', | |||||
click: function(link) { | |||||
if(me.cur_toolbar) | |||||
$(me.cur_toolbar).toggle(false); | |||||
if(!link.toolbar) | |||||
me.make_link_toolbar(link); | |||||
if(link.toolbar) { | |||||
me.cur_toolbar = link.toolbar; | |||||
$(me.cur_toolbar).toggle(true); | |||||
} | |||||
} | |||||
}); | |||||
this.tree.rootnode.$a | |||||
.data('node-data', {value: "Sitemap", expandable:1}) | |||||
.click(); | |||||
}, | |||||
make_link_toolbar: function(link) { | |||||
var data = $(link).data('node-data'); | |||||
if(!data) return; | |||||
link.toolbar = $('<span class="tree-node-toolbar"></span>').insertAfter(link); | |||||
// edit | |||||
var node_links = []; | |||||
node_links.push('<a onclick="frappe.website.sitemap.open();">'+frappe._('Edit')+'</a>'); | |||||
node_links.push('<a onclick="frappe.website.sitemap.move();">'+frappe._('Move')+'</a>'); | |||||
node_links.push('<a onclick="frappe.website.sitemap.up_or_down(\'up\');">'+frappe._('Up')+'</a>'); | |||||
node_links.push('<a onclick="frappe.website.sitemap.up_or_down(\'down\');">'+frappe._('Down')+'</a>'); | |||||
// if(data.expandable) { | |||||
// node_links.push('<a onclick="frappe.website.sitemap.new_node();">' + frappe._('Add Child') + '</a>'); | |||||
// } | |||||
// | |||||
// node_links.push('<a onclick="frappe.website.sitemap.delete()">' + frappe._('Delete') + '</a>'); | |||||
link.toolbar.append(node_links.join(" | ")); | |||||
}, | |||||
new_node: function() { | |||||
var me = this; | |||||
var fields = [ | |||||
{fieldtype:'Data', fieldname: 'name_field', | |||||
label:'New ' + me.ctype + ' Name', reqd:true}, | |||||
{fieldtype:'Select', fieldname:'is_group', label:'Group Node', options:'No\nYes', | |||||
description: frappe._("Further nodes can be only created under 'Group' type nodes")}, | |||||
{fieldtype:'Button', fieldname:'create_new', label:'Create New' } | |||||
] | |||||
if(me.ctype == "Sales Person") { | |||||
fields.splice(-1, 0, {fieldtype:'Link', fieldname:'employee', label:'Employee', | |||||
options:'Employee', description: frappe._("Please enter Employee Id of this sales parson")}); | |||||
} | |||||
// the dialog | |||||
var d = new frappe.ui.Dialog({ | |||||
title: frappe._('New ') + frappe._(me.ctype), | |||||
fields: fields | |||||
}) | |||||
d.set_value("is_group", "No"); | |||||
// create | |||||
$(d.fields_dict.create_new.input).click(function() { | |||||
var btn = this; | |||||
$(btn).set_working(); | |||||
var v = d.get_values(); | |||||
if(!v) return; | |||||
var node = me.selected_node(); | |||||
v.parent = node.data('label'); | |||||
v.ctype = me.ctype; | |||||
return frappe.call({ | |||||
method: 'erpnext.selling.page.sales_browser.sales_browser.add_node', | |||||
args: v, | |||||
callback: function() { | |||||
$(btn).done_working(); | |||||
d.hide(); | |||||
node.trigger('reload'); | |||||
} | |||||
}) | |||||
}); | |||||
d.show(); | |||||
}, | |||||
selected_node: function() { | |||||
return this.tree.$w.find('.tree-link.selected'); | |||||
}, | |||||
open: function() { | |||||
var node = this.selected_node(); | |||||
frappe.set_route("Form", "Website Sitemap", node.data("label")); | |||||
}, | |||||
up_or_down: function(up_or_down) { | |||||
var node = this.tree.get_selected_node(); | |||||
frappe.call({ | |||||
method: "frappe.website.page.sitemap_browser.sitemap_browser.move", | |||||
args: { | |||||
"name": node.label, | |||||
"up_or_down": up_or_down | |||||
}, | |||||
callback: function(r) { | |||||
(node.parent_node || node).reload(); | |||||
} | |||||
}); | |||||
}, | |||||
move: function() { | |||||
var me = this; | |||||
var node = this.selected_node(); | |||||
if(!this.move_dialog) { | |||||
this.move_dialog = new frappe.ui.Dialog({ | |||||
title: frappe._("Move"), | |||||
fields: [ | |||||
{ | |||||
fieldtype: "Link", | |||||
fieldname: "new_parent", | |||||
label: "New Parent", | |||||
reqd: 1, | |||||
options: "Website Sitemap" | |||||
}, | |||||
{ | |||||
fieldtype: "Button", | |||||
fieldname: "update", | |||||
label: "Update", | |||||
} | |||||
] | |||||
}); | |||||
this.move_dialog.get_input("update").on("click", function() { | |||||
var values = me.move_dialog.get_values(); | |||||
if(!values) return; | |||||
frappe.call({ | |||||
method: "frappe.website.page.sitemap_browser.sitemap_browser.update_parent", | |||||
args: { | |||||
"name": node.data("label"), | |||||
"new_parent": values.new_parent | |||||
}, | |||||
callback: function(r) { | |||||
me.move_dialog.hide(); | |||||
me.tree.rootnode.reload(); | |||||
} | |||||
}); | |||||
}); | |||||
} | |||||
this.move_dialog.show(); | |||||
this.move_dialog.get_input("new_parent").val(""); | |||||
} | |||||
}); |
@@ -0,0 +1,72 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
from frappe.website.render import clear_cache | |||||
@frappe.whitelist() | |||||
def get_children(parent=None): | |||||
if not frappe.has_permission("Website Sitemap"): | |||||
raise frappe.PermissionError | |||||
if parent=="Sitemap": | |||||
parent = "" | |||||
return frappe.conn.sql("""select name as value, 1 as expandable from `tabWebsite Sitemap` where | |||||
ifnull(parent_website_sitemap, '')=%s order by -idx desc""", parent, as_dict=True) | |||||
@frappe.whitelist() | |||||
def move(name, up_or_down): | |||||
ret = None | |||||
if not frappe.has_permission("Website Sitemap"): | |||||
raise frappe.PermissionError | |||||
sitemap = frappe.doc("Website Sitemap", name) | |||||
if up_or_down=="up": | |||||
if sitemap.idx > 0: | |||||
prev = frappe.doc("Website Sitemap", { | |||||
"parent_website_sitemap": sitemap.parent_website_sitemap, | |||||
"idx": sitemap.idx - 1 | |||||
}) | |||||
if prev.name: | |||||
prev.idx = prev.idx + 1 | |||||
prev.save() | |||||
sitemap.idx = sitemap.idx - 1 | |||||
sitemap.save() | |||||
ret = "ok" | |||||
else: | |||||
nexts = frappe.doc("Website Sitemap", { | |||||
"parent_website_sitemap": sitemap.parent_website_sitemap, | |||||
"idx": sitemap.idx + 1 | |||||
}) | |||||
if nexts.name: | |||||
nexts.idx = nexts.idx - 1 | |||||
nexts.save() | |||||
sitemap.idx = sitemap.idx + 1 | |||||
sitemap.save() | |||||
ret = "ok" | |||||
clear_cache() | |||||
@frappe.whitelist() | |||||
def update_parent(name, new_parent): | |||||
if not frappe.has_permission("Website Sitemap"): | |||||
raise frappe.PermissionError | |||||
sitemap = frappe.doc("Website Sitemap", name) | |||||
if sitemap.ref_doctype: | |||||
generator = frappe.bean(sitemap.ref_doctype, sitemap.docname) | |||||
if not generator.meta.has_field("parent_website_sitemap"): | |||||
frappe.throw("Does not allow moving.") | |||||
generator.doc.parent_website_sitemap = new_parent | |||||
generator.save() | |||||
else: | |||||
frappe.msgprint("Template Pages cannot be moved.") | |||||
clear_cache() | |||||
@@ -0,0 +1,37 @@ | |||||
[ | |||||
{ | |||||
"creation": "2014-02-18 10:47:22", | |||||
"docstatus": 0, | |||||
"modified": "2014-02-18 10:47:22", | |||||
"modified_by": "Administrator", | |||||
"owner": "Administrator" | |||||
}, | |||||
{ | |||||
"doctype": "Page", | |||||
"icon": "icon-sitemap", | |||||
"module": "Website", | |||||
"name": "__common__", | |||||
"page_name": "sitemap-browser", | |||||
"standard": "Yes", | |||||
"title": "Sitemap Browser" | |||||
}, | |||||
{ | |||||
"doctype": "Page Role", | |||||
"name": "__common__", | |||||
"parent": "sitemap-browser", | |||||
"parentfield": "roles", | |||||
"parenttype": "Page" | |||||
}, | |||||
{ | |||||
"doctype": "Page", | |||||
"name": "sitemap-browser" | |||||
}, | |||||
{ | |||||
"doctype": "Page Role", | |||||
"role": "Website Manager" | |||||
}, | |||||
{ | |||||
"doctype": "Page Role", | |||||
"role": "System Manager" | |||||
} | |||||
] |
@@ -62,6 +62,13 @@ frappe.module_page["Website"] = [ | |||||
icon: "icon-wrench", | icon: "icon-wrench", | ||||
right: true, | right: true, | ||||
items: [ | items: [ | ||||
{ | |||||
"route":"sitemap-browser", | |||||
"label":frappe._("Sitemap Browser"), | |||||
"description":frappe._("View or manage Website Sitemap tree."), | |||||
doctype:"Website Settings", | |||||
icon: "icon-sitemap" | |||||
}, | |||||
{ | { | ||||
"route":"Form/Website Settings", | "route":"Form/Website Settings", | ||||
"label":frappe._("Website Settings"), | "label":frappe._("Website Settings"), | ||||
@@ -57,5 +57,5 @@ def build_sitemap_options(path): | |||||
# determine templates to be used | # determine templates to be used | ||||
if not sitemap_options.base_template_path: | if not sitemap_options.base_template_path: | ||||
sitemap_options.base_template_path = "templates/base.html" | sitemap_options.base_template_path = "templates/base.html" | ||||
return sitemap_options | return sitemap_options |
@@ -23,6 +23,8 @@ class WebsiteGenerator(DocListController): | |||||
self.doc.fields[self._website_config.page_name_field] = page_name | self.doc.fields[self._website_config.page_name_field] = page_name | ||||
else: | else: | ||||
frappe.conn.set(self.doc, self._website_config.page_name_field, page_name) | frappe.conn.set(self.doc, self._website_config.page_name_field, page_name) | ||||
return page_name | |||||
def get_parent_website_sitemap(self): | def get_parent_website_sitemap(self): | ||||
return self.doc.parent_website_sitemap | return self.doc.parent_website_sitemap | ||||
@@ -94,13 +96,17 @@ class WebsiteGenerator(DocListController): | |||||
opts.public_read = 1 | opts.public_read = 1 | ||||
def get_page_name(self): | def get_page_name(self): | ||||
if not self._get_page_name(): | |||||
self.set_page_name() | |||||
page_name = self._get_page_name() | |||||
if not page_name: | |||||
page_name = self.set_page_name() | |||||
return self._get_page_name() | return self._get_page_name() | ||||
def _get_page_name(self): | def _get_page_name(self): | ||||
return self.doc.fields.get(self._website_config.page_name_field) | |||||
if self.meta.has_field(self._website_config.page_name_field): | |||||
return self.doc.fields.get(self._website_config.page_name_field) | |||||
else: | |||||
return cleanup_page_name(self.get_page_title()) | |||||
def get_page_title(self): | def get_page_title(self): | ||||
return self.doc.title or (self.doc.name.replace("-", " ").replace("_", " ").title()) | return self.doc.title or (self.doc.name.replace("-", " ").replace("_", " ").title()) |