@@ -1,5 +1,5 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | ||||
# MIT License. See license.txt | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe | import frappe | ||||
@@ -17,7 +17,7 @@ class Page(Document): | |||||
self.name = self.page_name.lower().replace('"','').replace("'",'').\ | self.name = self.page_name.lower().replace('"','').replace("'",'').\ | ||||
replace(' ', '-')[:20] | replace(' ', '-')[:20] | ||||
if frappe.db.exists('Page',self.name): | if frappe.db.exists('Page',self.name): | ||||
cnt = frappe.db.sql("""select name from tabPage | |||||
cnt = frappe.db.sql("""select name from tabPage | |||||
where name like "%s-%%" order by name desc limit 1""" % self.name) | where name like "%s-%%" order by name desc limit 1""" % self.name) | ||||
if cnt: | if cnt: | ||||
cnt = cint(cnt[0][0].split('-')[-1]) + 1 | cnt = cint(cnt[0][0].split('-')[-1]) + 1 | ||||
@@ -34,29 +34,29 @@ class Page(Document): | |||||
from frappe import conf | from frappe import conf | ||||
from frappe.core.doctype.doctype.doctype import make_module_and_roles | from frappe.core.doctype.doctype.doctype import make_module_and_roles | ||||
make_module_and_roles(self, "roles") | make_module_and_roles(self, "roles") | ||||
if not frappe.flags.in_import and getattr(conf,'developer_mode', 0) and self.standard=='Yes': | if not frappe.flags.in_import and getattr(conf,'developer_mode', 0) and self.standard=='Yes': | ||||
from frappe.modules.export_file import export_to_files | from frappe.modules.export_file import export_to_files | ||||
from frappe.modules import get_module_path, scrub | from frappe.modules import get_module_path, scrub | ||||
import os | import os | ||||
export_to_files(record_list=[['Page', self.name]]) | export_to_files(record_list=[['Page', self.name]]) | ||||
# write files | # write files | ||||
path = os.path.join(get_module_path(self.module), 'page', scrub(self.name), scrub(self.name)) | path = os.path.join(get_module_path(self.module), 'page', scrub(self.name), scrub(self.name)) | ||||
# js | # js | ||||
if not os.path.exists(path + '.js'): | if not os.path.exists(path + '.js'): | ||||
with open(path + '.js', 'w') as f: | with open(path + '.js', 'w') as f: | ||||
f.write("""frappe.pages['%s'].onload = function(wrapper) { | |||||
f.write("""frappe.pages['%s'].onload = function(wrapper) { | |||||
frappe.ui.make_app_page({ | frappe.ui.make_app_page({ | ||||
parent: wrapper, | parent: wrapper, | ||||
title: '%s', | title: '%s', | ||||
single_column: true | single_column: true | ||||
}); | |||||
}); | |||||
}""" % (self.name, self.title)) | }""" % (self.name, self.title)) | ||||
def as_dict(self): | |||||
d = super(Page, self).as_dict() | |||||
def as_dict(self, no_nulls=False): | |||||
d = super(Page, self).as_dict(no_nulls=no_nulls) | |||||
for key in ("script", "style", "content"): | for key in ("script", "style", "content"): | ||||
d[key] = self.get(key) | d[key] = self.get(key) | ||||
return d | return d | ||||
@@ -64,7 +64,7 @@ class Page(Document): | |||||
def load_assets(self): | def load_assets(self): | ||||
from frappe.modules import get_module_path, scrub | from frappe.modules import get_module_path, scrub | ||||
import os | import os | ||||
path = os.path.join(get_module_path(self.module), 'page', scrub(self.name)) | path = os.path.join(get_module_path(self.module), 'page', scrub(self.name)) | ||||
# script | # script | ||||
@@ -78,14 +78,13 @@ class Page(Document): | |||||
if os.path.exists(fpath): | if os.path.exists(fpath): | ||||
with open(fpath, 'r') as f: | with open(fpath, 'r') as f: | ||||
self.style = f.read() | self.style = f.read() | ||||
# html | # html | ||||
fpath = os.path.join(path, scrub(self.name) + '.html') | fpath = os.path.join(path, scrub(self.name) + '.html') | ||||
if os.path.exists(fpath): | if os.path.exists(fpath): | ||||
with open(fpath, 'r') as f: | with open(fpath, 'r') as f: | ||||
self.content = f.read() | self.content = f.read() | ||||
if frappe.lang != 'en': | if frappe.lang != 'en': | ||||
from frappe.translate import get_lang_js | from frappe.translate import get_lang_js | ||||
self.script += get_lang_js("page", self.name) | self.script += get_lang_js("page", self.name) | ||||
@@ -54,7 +54,7 @@ def export_json(doctype, name, path): | |||||
d.set("parent", None) | d.set("parent", None) | ||||
d.set("name", None) | d.set("name", None) | ||||
d.set("__islocal", 1) | d.set("__islocal", 1) | ||||
outfile.write(json.dumps([d], default=json_handler, indent=1, sort_keys=True)) | |||||
outfile.write(json.dumps(doc, default=json_handler, indent=1, sort_keys=True)) | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def export_fixture(doctype, name, app): | def export_fixture(doctype, name, app): | ||||
@@ -138,12 +138,18 @@ class BaseDocument(object): | |||||
def is_new(self): | def is_new(self): | ||||
return self.get("__islocal") | return self.get("__islocal") | ||||
def as_dict(self): | |||||
def as_dict(self, no_nulls=False): | |||||
doc = self.get_valid_dict() | doc = self.get_valid_dict() | ||||
doc["doctype"] = self.doctype | doc["doctype"] = self.doctype | ||||
for df in self.meta.get_table_fields(): | for df in self.meta.get_table_fields(): | ||||
children = self.get(df.fieldname) or [] | children = self.get(df.fieldname) or [] | ||||
doc[df.fieldname] = [d.as_dict() for d in children] | |||||
doc[df.fieldname] = [d.as_dict(no_nulls=no_nulls) for d in children] | |||||
if no_nulls: | |||||
for k in doc.keys(): | |||||
if doc[k] is None: | |||||
del doc[k] | |||||
return doc | return doc | ||||
def get_table_field_doctype(self, fieldname): | def get_table_field_doctype(self, fieldname): | ||||
@@ -1,5 +1,5 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | ||||
# MIT License. See license.txt | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import json | import json | ||||
@@ -22,7 +22,7 @@ from werkzeug.exceptions import NotFound, Forbidden | |||||
def report_error(status_code): | def report_error(status_code): | ||||
if status_code!=404 or frappe.conf.logging: | if status_code!=404 or frappe.conf.logging: | ||||
frappe.errprint(frappe.utils.get_traceback()) | frappe.errprint(frappe.utils.get_traceback()) | ||||
response = build_response("json") | response = build_response("json") | ||||
response.status_code = status_code | response.status_code = status_code | ||||
return response | return response | ||||
@@ -30,7 +30,7 @@ def report_error(status_code): | |||||
def build_response(response_type=None): | def build_response(response_type=None): | ||||
if "docs" in frappe.local.response and not frappe.local.response.docs: | if "docs" in frappe.local.response and not frappe.local.response.docs: | ||||
del frappe.local.response["docs"] | del frappe.local.response["docs"] | ||||
response_type_map = { | response_type_map = { | ||||
'csv': as_csv, | 'csv': as_csv, | ||||
'download': as_raw, | 'download': as_raw, | ||||
@@ -38,9 +38,9 @@ def build_response(response_type=None): | |||||
'page': as_page, | 'page': as_page, | ||||
'redirect': redirect | 'redirect': redirect | ||||
} | } | ||||
return response_type_map[frappe.response.get('type') or response_type]() | return response_type_map[frappe.response.get('type') or response_type]() | ||||
def as_csv(): | def as_csv(): | ||||
response = Response() | response = Response() | ||||
response.headers["Content-Type"] = "text/csv; charset: utf-8" | response.headers["Content-Type"] = "text/csv; charset: utf-8" | ||||
@@ -62,7 +62,7 @@ def as_json(): | |||||
response = gzip(json.dumps(frappe.local.response, default=json_handler, separators=(',',':')), | response = gzip(json.dumps(frappe.local.response, default=json_handler, separators=(',',':')), | ||||
response=response) | response=response) | ||||
return response | return response | ||||
def make_logs(): | def make_logs(): | ||||
"""make strings for msgprint and errprint""" | """make strings for msgprint and errprint""" | ||||
if frappe.error_log: | if frappe.error_log: | ||||
@@ -72,21 +72,21 @@ def make_logs(): | |||||
if frappe.local.message_log: | if frappe.local.message_log: | ||||
frappe.response['_server_messages'] = json.dumps([frappe.utils.cstr(d) for | frappe.response['_server_messages'] = json.dumps([frappe.utils.cstr(d) for | ||||
d in frappe.local.message_log]) | d in frappe.local.message_log]) | ||||
if frappe.debug_log and frappe.conf.get("logging") or False: | if frappe.debug_log and frappe.conf.get("logging") or False: | ||||
frappe.response['_debug_messages'] = json.dumps(frappe.local.debug_log) | frappe.response['_debug_messages'] = json.dumps(frappe.local.debug_log) | ||||
def gzip(data, response): | def gzip(data, response): | ||||
data = data.encode('utf-8') | data = data.encode('utf-8') | ||||
orig_len = len(data) | orig_len = len(data) | ||||
if accept_gzip() and orig_len>512: | if accept_gzip() and orig_len>512: | ||||
data = compressBuf(data) | data = compressBuf(data) | ||||
response.headers["Content-Encoding"] = "gzip" | response.headers["Content-Encoding"] = "gzip" | ||||
response.headers["Content-Length"] = str(len(data)) | response.headers["Content-Length"] = str(len(data)) | ||||
response.data = data | response.data = data | ||||
return response | return response | ||||
def accept_gzip(): | def accept_gzip(): | ||||
if "gzip" in frappe.get_request_header("HTTP_ACCEPT_ENCODING", ""): | if "gzip" in frappe.get_request_header("HTTP_ACCEPT_ENCODING", ""): | ||||
return True | return True | ||||
@@ -97,7 +97,7 @@ def compressBuf(buf): | |||||
zfile.write(buf) | zfile.write(buf) | ||||
zfile.close() | zfile.close() | ||||
return zbuf.getvalue() | return zbuf.getvalue() | ||||
def json_handler(obj): | def json_handler(obj): | ||||
"""serialize non-serializable data for json""" | """serialize non-serializable data for json""" | ||||
# serialize date | # serialize date | ||||
@@ -105,20 +105,22 @@ def json_handler(obj): | |||||
return unicode(obj) | return unicode(obj) | ||||
elif isinstance(obj, LocalProxy): | elif isinstance(obj, LocalProxy): | ||||
return unicode(obj) | return unicode(obj) | ||||
elif isinstance(obj, frappe.model.document.Document): | |||||
return obj.as_dict() | |||||
elif isinstance(obj, frappe.model.document.BaseDocument): | |||||
doc = obj.as_dict(no_nulls=True) | |||||
return doc | |||||
else: | else: | ||||
raise TypeError, """Object of type %s with value of %s is not JSON serializable""" % \ | raise TypeError, """Object of type %s with value of %s is not JSON serializable""" % \ | ||||
(type(obj), repr(obj)) | (type(obj), repr(obj)) | ||||
def as_page(): | def as_page(): | ||||
"""print web page""" | """print web page""" | ||||
from frappe.website.render import render | from frappe.website.render import render | ||||
return render(frappe.response['page_name'], http_status_code=frappe.response.get("http_status_code")) | return render(frappe.response['page_name'], http_status_code=frappe.response.get("http_status_code")) | ||||
def redirect(): | def redirect(): | ||||
return werkzeug.utils.redirect(frappe.response.location) | return werkzeug.utils.redirect(frappe.response.location) | ||||
def download_backup(path): | def download_backup(path): | ||||
try: | try: | ||||
frappe.only_for(("System Manager", "Administrator")) | frappe.only_for(("System Manager", "Administrator")) | ||||
@@ -145,7 +147,7 @@ def send_private_file(path): | |||||
response = Response(wrap_file(frappe.local.request.environ, f)) | response = Response(wrap_file(frappe.local.request.environ, f)) | ||||
response.headers.add('Content-Disposition', 'attachment', filename=filename) | response.headers.add('Content-Disposition', 'attachment', filename=filename) | ||||
response.headers['Content-Type'] = mimetypes.guess_type(filename)[0] or 'application/octet-stream' | response.headers['Content-Type'] = mimetypes.guess_type(filename)[0] or 'application/octet-stream' | ||||
return response | return response | ||||
def handle_session_stopped(): | def handle_session_stopped(): | ||||
@@ -9,8 +9,8 @@ $.extend(frappe, { | |||||
if(frappe._assets_loaded.indexOf(url)!==-1) return; | if(frappe._assets_loaded.indexOf(url)!==-1) return; | ||||
$.ajax({ | $.ajax({ | ||||
url: url, | url: url, | ||||
async: false, | |||||
dataType: "text", | |||||
async: false, | |||||
dataType: "text", | |||||
success: function(data) { | success: function(data) { | ||||
if(url.split(".").splice(-1) == "js") { | if(url.split(".").splice(-1) == "js") { | ||||
var el = document.createElement('script'); | var el = document.createElement('script'); | ||||
@@ -58,13 +58,13 @@ $.extend(frappe, { | |||||
if(opts.btn) { | if(opts.btn) { | ||||
$(opts.btn).prop("disabled", true); | $(opts.btn).prop("disabled", true); | ||||
} | } | ||||
if(opts.msg) { | if(opts.msg) { | ||||
$(opts.msg).toggle(false); | $(opts.msg).toggle(false); | ||||
} | } | ||||
if(!opts.args) opts.args = {}; | if(!opts.args) opts.args = {}; | ||||
// get or post? | // get or post? | ||||
if(!opts.args._type) { | if(!opts.args._type) { | ||||
opts.args._type = opts.type || "GET"; | opts.args._type = opts.type || "GET"; | ||||
@@ -82,17 +82,17 @@ $.extend(frappe, { | |||||
} | } | ||||
}); | }); | ||||
if(!opts.no_spinner) { | |||||
if(!opts.no_spinner) { | |||||
NProgress.start(); | NProgress.start(); | ||||
} | } | ||||
}, | }, | ||||
process_response: function(opts, data) { | process_response: function(opts, data) { | ||||
if(!opts.no_spinner) NProgress.done(); | if(!opts.no_spinner) NProgress.done(); | ||||
if(opts.btn) { | if(opts.btn) { | ||||
$(opts.btn).prop("disabled", false); | $(opts.btn).prop("disabled", false); | ||||
} | } | ||||
if(data.exc) { | if(data.exc) { | ||||
if(opts.btn) { | if(opts.btn) { | ||||
$(opts.btn).addClass("btn-danger"); | $(opts.btn).addClass("btn-danger"); | ||||
@@ -145,7 +145,7 @@ $.extend(frappe, { | |||||
</div>\ | </div>\ | ||||
</div>\ | </div>\ | ||||
</div>').appendTo(document.body); | </div>').appendTo(document.body); | ||||
return modal; | return modal; | ||||
}, | }, | ||||
msgprint: function(html, title) { | msgprint: function(html, title) { | ||||
@@ -189,19 +189,19 @@ $.extend(frappe, { | |||||
if(frappe.supports_pjax()) { | if(frappe.supports_pjax()) { | ||||
// hack for chrome's onload popstate call | // hack for chrome's onload popstate call | ||||
window.initial_href = window.location.href | window.initial_href = window.location.href | ||||
$(document).on("click", "#wrap a", frappe.handle_click); | $(document).on("click", "#wrap a", frappe.handle_click); | ||||
$(window).on("popstate", function(event) { | $(window).on("popstate", function(event) { | ||||
// hack for chrome's onload popstate call | // hack for chrome's onload popstate call | ||||
if(window.initial_href==location.href && window.previous_href==undefined) { | if(window.initial_href==location.href && window.previous_href==undefined) { | ||||
frappe.set_force_reload(true); | frappe.set_force_reload(true); | ||||
return; | return; | ||||
} | } | ||||
window.previous_href = location.href; | window.previous_href = location.href; | ||||
var state = event.originalEvent.state; | var state = event.originalEvent.state; | ||||
if(state) { | if(state) { | ||||
frappe.render_json(state); | frappe.render_json(state); | ||||
} else { | } else { | ||||
@@ -213,7 +213,7 @@ $.extend(frappe, { | |||||
handle_click: function(event) { | handle_click: function(event) { | ||||
// taken from jquery pjax | // taken from jquery pjax | ||||
var link = event.currentTarget | var link = event.currentTarget | ||||
if (link.tagName.toUpperCase() !== 'A') | if (link.tagName.toUpperCase() !== 'A') | ||||
throw "using pjax requires an anchor element" | throw "using pjax requires an anchor element" | ||||
@@ -221,7 +221,7 @@ $.extend(frappe, { | |||||
// links in a new tab as normal. | // links in a new tab as normal. | ||||
if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) | if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) | ||||
return | return | ||||
// Ignore cross origin links | // Ignore cross origin links | ||||
if ( location.protocol !== link.protocol || location.hostname !== link.hostname ) | if ( location.protocol !== link.protocol || location.hostname !== link.hostname ) | ||||
return | return | ||||
@@ -230,15 +230,15 @@ $.extend(frappe, { | |||||
if (link.hash && link.href.replace(link.hash, '') === | if (link.hash && link.href.replace(link.hash, '') === | ||||
location.href.replace(location.hash, '')) | location.href.replace(location.hash, '')) | ||||
return | return | ||||
// Ignore empty anchor "foo.html#" | // Ignore empty anchor "foo.html#" | ||||
if (link.href === location.href + '#') | if (link.href === location.href + '#') | ||||
return | return | ||||
// our custom logic | // our custom logic | ||||
if (link.href.indexOf("cmd=")!==-1 || link.hasAttribute("no-pjax")) | if (link.href.indexOf("cmd=")!==-1 || link.hasAttribute("no-pjax")) | ||||
return | return | ||||
event.preventDefault() | event.preventDefault() | ||||
frappe.load_via_ajax(link.href); | frappe.load_via_ajax(link.href); | ||||
@@ -247,12 +247,12 @@ $.extend(frappe, { | |||||
// console.log("calling ajax"); | // console.log("calling ajax"); | ||||
window.previous_href = href; | window.previous_href = href; | ||||
history.pushState(null, null, href); | history.pushState(null, null, href); | ||||
//NProgress.start(); | //NProgress.start(); | ||||
$.ajax({ url: href, cache: false }).done(function(data) { | $.ajax({ url: href, cache: false }).done(function(data) { | ||||
history.replaceState(data, data.title, href); | history.replaceState(data, data.title, href); | ||||
$("html, body").animate({ scrollTop: 0 }, "slow"); | $("html, body").animate({ scrollTop: 0 }, "slow"); | ||||
frappe.render_json(data); | |||||
frappe.render_json(data); | |||||
}).always(function() { | }).always(function() { | ||||
//NProgress.done(); | //NProgress.done(); | ||||
}).fail(function(xhr, status, error) { | }).fail(function(xhr, status, error) { | ||||
@@ -289,17 +289,17 @@ $.extend(frappe, { | |||||
} | } | ||||
}); | }); | ||||
if(data.title) $("title").html(data.title); | if(data.title) $("title").html(data.title); | ||||
// change id of current page | // change id of current page | ||||
$(".page-container").attr("id", "page-" + data.path); | $(".page-container").attr("id", "page-" + data.path); | ||||
window.ga && ga('send', 'pageview', location.pathname); | window.ga && ga('send', 'pageview', location.pathname); | ||||
$(document).trigger("page-change"); | $(document).trigger("page-change"); | ||||
} | } | ||||
}, | }, | ||||
set_force_reload: function(reload) { | set_force_reload: function(reload) { | ||||
// learned this from twitter's implementation | // learned this from twitter's implementation | ||||
window.history.replaceState({"reload": reload}, | |||||
window.history.replaceState({"reload": reload}, | |||||
window.document.title, location.href); | window.document.title, location.href); | ||||
}, | }, | ||||
supports_pjax: function() { | supports_pjax: function() { | ||||
@@ -345,19 +345,19 @@ $.extend(frappe, { | |||||
$("[data-html-block='breadcrumbs'] .breadcrumb").toggleClass("hidden", | $("[data-html-block='breadcrumbs'] .breadcrumb").toggleClass("hidden", | ||||
!$("[data-html-block='breadcrumbs']").text().trim() || | !$("[data-html-block='breadcrumbs']").text().trim() || | ||||
$("[data-html-block='breadcrumbs']").text().trim()==$("[data-html-block='header']").text().trim()); | $("[data-html-block='breadcrumbs']").text().trim()==$("[data-html-block='header']").text().trim()); | ||||
// to show full content width, when no sidebar content | // to show full content width, when no sidebar content | ||||
var sidebar_has_content = !!$("[data-html-block='sidebar']").html().trim(); | |||||
$(".page-sidebar, .toggle-sidebar").toggleClass("hidden", !sidebar_has_content); | |||||
$(".page-sidebar").toggleClass("col-sm-push-9", sidebar_has_content); | |||||
$(".page-content").toggleClass("col-sm-12", !sidebar_has_content); | |||||
$(".page-content").toggleClass("col-sm-9 col-sm-pull-3", sidebar_has_content); | |||||
// var sidebar_has_content = !!$("[data-html-block='sidebar']").html().trim(); | |||||
// $(".page-sidebar, .toggle-sidebar").toggleClass("hidden", !sidebar_has_content); | |||||
// $(".page-sidebar").toggleClass("col-sm-push-9", sidebar_has_content); | |||||
// $(".page-content").toggleClass("col-sm-12", !sidebar_has_content); | |||||
// $(".page-content").toggleClass("col-sm-9 col-sm-pull-3", sidebar_has_content); | |||||
// if everything in the sub-header is hidden, hide the sub-header | // if everything in the sub-header is hidden, hide the sub-header | ||||
var hide_sub_header = $(".page-sub-header .row").children().length === $(".page-sub-header .row").find(".hidden").length; | var hide_sub_header = $(".page-sub-header .row").children().length === $(".page-sub-header .row").find(".hidden").length; | ||||
$(".page-sub-header").toggleClass("hidden", hide_sub_header); | $(".page-sub-header").toggleClass("hidden", hide_sub_header); | ||||
// collapse sidebar in mobile view on page change | // collapse sidebar in mobile view on page change | ||||
if(!$(".page-sidebar").hasClass("hidden-xs")) { | if(!$(".page-sidebar").hasClass("hidden-xs")) { | ||||
$(".toggle-sidebar").trigger("click"); | $(".toggle-sidebar").trigger("click"); | ||||
@@ -388,7 +388,7 @@ function get_url_arg(name) { | |||||
if(results == null) | if(results == null) | ||||
return ""; | return ""; | ||||
else | else | ||||
return decodeURIComponent(results[1]); | |||||
return decodeURIComponent(results[1]); | |||||
} | } | ||||
function make_query_string(obj) { | function make_query_string(obj) { | ||||
@@ -468,7 +468,7 @@ function remove_script_and_style(txt) { | |||||
} | } | ||||
function is_html(txt) { | function is_html(txt) { | ||||
if(txt.indexOf("<br>")==-1 && txt.indexOf("<p")==-1 | |||||
if(txt.indexOf("<br>")==-1 && txt.indexOf("<p")==-1 | |||||
&& txt.indexOf("<img")==-1 && txt.indexOf("<div")==-1) { | && txt.indexOf("<img")==-1 && txt.indexOf("<div")==-1) { | ||||
return false; | return false; | ||||
} | } | ||||
@@ -491,21 +491,21 @@ $(document).ready(function() { | |||||
window.logged_in = getCookie("sid") && getCookie("sid")!=="Guest"; | window.logged_in = getCookie("sid") && getCookie("sid")!=="Guest"; | ||||
$("#website-login").toggleClass("hide", logged_in ? true : false); | $("#website-login").toggleClass("hide", logged_in ? true : false); | ||||
$("#website-post-login").toggleClass("hide", logged_in ? false : true); | $("#website-post-login").toggleClass("hide", logged_in ? false : true); | ||||
$(".toggle-sidebar").on("click", function() { | $(".toggle-sidebar").on("click", function() { | ||||
$(".page-sidebar").toggleClass("hidden-xs"); | $(".page-sidebar").toggleClass("hidden-xs"); | ||||
$(".toggle-sidebar i").toggleClass("icon-rotate-180"); | $(".toggle-sidebar i").toggleClass("icon-rotate-180"); | ||||
}); | }); | ||||
// switch to app link | // switch to app link | ||||
if(getCookie("system_user")==="yes") { | if(getCookie("system_user")==="yes") { | ||||
$("#website-post-login .dropdown-menu").append('<li class="divider"></li>\ | $("#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>'); | <li><a href="/desk" no-pjax><i class="icon-fixed-width icon-th-large"></i> Switch To Desk</a></li>'); | ||||
} | } | ||||
frappe.render_user(); | frappe.render_user(); | ||||
frappe.setup_push_state() | frappe.setup_push_state() | ||||
$(document).trigger("page-change"); | $(document).trigger("page-change"); | ||||
}); | }); | ||||
@@ -42,7 +42,9 @@ def build_sitemap_options(path): | |||||
if not sitemap_options.no_sidebar: | if not sitemap_options.no_sidebar: | ||||
sitemap_options.children = get_route_children(sitemap_options.pathname, home_page) | sitemap_options.children = get_route_children(sitemap_options.pathname, home_page) | ||||
if not sitemap_options.children: | |||||
if not sitemap_options.children and sitemap_options.parent_website_route \ | |||||
and sitemap_options.parent_website_route!=home_page: | |||||
sitemap_options.children = get_route_children(sitemap_options.parent_website_route, home_page) | sitemap_options.children = get_route_children(sitemap_options.parent_website_route, home_page) | ||||
# determine templates to be used | # determine templates to be used | ||||
@@ -80,4 +82,4 @@ def get_route_children(pathname, home_page=None): | |||||
children = [frappe.get_doc("Website Route", pathname)] + children | children = [frappe.get_doc("Website Route", pathname)] + children | ||||
return children | |||||
return children |
@@ -1,5 +1,5 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | ||||
# MIT License. See license.txt | |||||
# MIT License. See license.txt | |||||
# metadata | # metadata | ||||
@@ -20,14 +20,14 @@ def get_meta(doctype, cached=True): | |||||
if frappe.local.lang != 'en': | if frappe.local.lang != 'en': | ||||
meta.set("__messages", frappe.get_lang_dict("doctype", doctype)) | meta.set("__messages", frappe.get_lang_dict("doctype", doctype)) | ||||
return meta | return meta | ||||
class FormMeta(Meta): | class FormMeta(Meta): | ||||
def __init__(self, doctype): | def __init__(self, doctype): | ||||
super(FormMeta, self).__init__(doctype) | super(FormMeta, self).__init__(doctype) | ||||
self.load_assets() | self.load_assets() | ||||
def load_assets(self): | def load_assets(self): | ||||
self.expand_selects() | self.expand_selects() | ||||
self.add_search_fields() | self.add_search_fields() | ||||
@@ -37,52 +37,52 @@ class FormMeta(Meta): | |||||
self.add_code() | self.add_code() | ||||
self.load_print_formats() | self.load_print_formats() | ||||
self.load_workflows() | self.load_workflows() | ||||
def as_dict(self): | |||||
d = super(FormMeta, self).as_dict() | |||||
def as_dict(self, no_nulls=False): | |||||
d = super(FormMeta, self).as_dict(no_nulls=no_nulls) | |||||
for k in ("__js", "__css", "__list_js", "__calendar_js", "__map_js", "__linked_with", "__messages"): | for k in ("__js", "__css", "__list_js", "__calendar_js", "__map_js", "__linked_with", "__messages"): | ||||
d[k] = self.get(k) | d[k] = self.get(k) | ||||
for i, df in enumerate(d.get("fields")): | for i, df in enumerate(d.get("fields")): | ||||
for k in ("link_doctype", "search_fields"): | for k in ("link_doctype", "search_fields"): | ||||
df[k] = self.get("fields")[i].get(k) | df[k] = self.get("fields")[i].get(k) | ||||
return d | return d | ||||
def add_code(self): | def add_code(self): | ||||
path = os.path.join(get_module_path(self.module), 'doctype', scrub(self.name)) | path = os.path.join(get_module_path(self.module), 'doctype', scrub(self.name)) | ||||
def _get_path(fname): | def _get_path(fname): | ||||
return os.path.join(path, scrub(fname)) | return os.path.join(path, scrub(fname)) | ||||
self._add_code(_get_path(self.name + '.js'), '__js') | self._add_code(_get_path(self.name + '.js'), '__js') | ||||
self._add_code(_get_path(self.name + '.css'), "__css") | self._add_code(_get_path(self.name + '.css'), "__css") | ||||
self._add_code(_get_path(self.name + '_list.js'), '__list_js') | self._add_code(_get_path(self.name + '_list.js'), '__list_js') | ||||
self._add_code(_get_path(self.name + '_calendar.js'), '__calendar_js') | self._add_code(_get_path(self.name + '_calendar.js'), '__calendar_js') | ||||
self._add_code(_get_path(self.name + '_map.js'), '__map_js') | self._add_code(_get_path(self.name + '_map.js'), '__map_js') | ||||
self.add_custom_script() | self.add_custom_script() | ||||
self.add_code_via_hook("doctype_js", "__js") | self.add_code_via_hook("doctype_js", "__js") | ||||
def _add_code(self, path, fieldname): | def _add_code(self, path, fieldname): | ||||
js = frappe.read_file(path) | js = frappe.read_file(path) | ||||
if js: | if js: | ||||
self.set(fieldname, (self.get(fieldname) or "") + "\n\n" + render_jinja(js)) | self.set(fieldname, (self.get(fieldname) or "") + "\n\n" + render_jinja(js)) | ||||
def add_code_via_hook(self, hook, fieldname): | def add_code_via_hook(self, hook, fieldname): | ||||
hook = "{}:{}".format(hook, self.name) | hook = "{}:{}".format(hook, self.name) | ||||
for app_name in frappe.get_installed_apps(): | for app_name in frappe.get_installed_apps(): | ||||
for file in frappe.get_hooks(hook, app_name=app_name): | for file in frappe.get_hooks(hook, app_name=app_name): | ||||
path = frappe.get_app_path(app_name, *file.strip("/").split("/")) | path = frappe.get_app_path(app_name, *file.strip("/").split("/")) | ||||
self._add_code(path, fieldname) | self._add_code(path, fieldname) | ||||
def add_custom_script(self): | def add_custom_script(self): | ||||
"""embed all require files""" | """embed all require files""" | ||||
# custom script | # custom script | ||||
custom = frappe.db.get_value("Custom Script", {"dt": self.name, | |||||
custom = frappe.db.get_value("Custom Script", {"dt": self.name, | |||||
"script_type": "Client"}, "script") or "" | "script_type": "Client"}, "script") or "" | ||||
self.set("__js", (self.get('__js') or '') + "\n\n" + custom) | self.set("__js", (self.get('__js') or '') + "\n\n" + custom) | ||||
def render_jinja(content): | def render_jinja(content): | ||||
if "{% include" in content: | if "{% include" in content: | ||||
content = frappe.get_jenv().from_string(content).render() | content = frappe.get_jenv().from_string(content).render() | ||||
@@ -92,9 +92,9 @@ class FormMeta(Meta): | |||||
for df in self.get("fields", {"fieldtype": "Select"}): | for df in self.get("fields", {"fieldtype": "Select"}): | ||||
if df.options and df.options.startswith("link:"): | if df.options and df.options.startswith("link:"): | ||||
df.link_doctype = df.options.split("\n")[0][5:] | df.link_doctype = df.options.split("\n")[0][5:] | ||||
df.options = '\n'.join([''] + [o.name for o in frappe.db.sql("""select | |||||
df.options = '\n'.join([''] + [o.name for o in frappe.db.sql("""select | |||||
name from `tab%s` where docstatus<2 order by name asc""" % df.link_doctype, as_dict=1)]) | name from `tab%s` where docstatus<2 order by name asc""" % df.link_doctype, as_dict=1)]) | ||||
def add_search_fields(self): | def add_search_fields(self): | ||||
"""add search fields found in the doctypes indicated by link fields' options""" | """add search fields found in the doctypes indicated by link fields' options""" | ||||
for df in self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]}): | for df in self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]}): | ||||
@@ -114,7 +114,7 @@ class FormMeta(Meta): | |||||
links = dict(links) | links = dict(links) | ||||
if not links: | |||||
if not links: | |||||
return {} | return {} | ||||
ret = {} | ret = {} | ||||
@@ -122,21 +122,21 @@ class FormMeta(Meta): | |||||
for dt in links: | for dt in links: | ||||
ret[dt] = { "fieldname": links[dt] } | ret[dt] = { "fieldname": links[dt] } | ||||
for grand_parent, options in frappe.db.sql("""select parent, options from tabDocField | |||||
where fieldtype="Table" | |||||
and options in (select name from tabDocType | |||||
for grand_parent, options in frappe.db.sql("""select parent, options from tabDocField | |||||
where fieldtype="Table" | |||||
and options in (select name from tabDocType | |||||
where istable=1 and name in (%s))""" % ", ".join(["%s"] * len(links)) ,tuple(links)): | where istable=1 and name in (%s))""" % ", ".join(["%s"] * len(links)) ,tuple(links)): | ||||
ret[grand_parent] = {"child_doctype": options, "fieldname": links[options] } | ret[grand_parent] = {"child_doctype": options, "fieldname": links[options] } | ||||
if options in ret: | if options in ret: | ||||
del ret[options] | del ret[options] | ||||
self.set("__linked_with", ret) | self.set("__linked_with", ret) | ||||
def load_print_formats(self): | def load_print_formats(self): | ||||
frappe.response.docs.extend(frappe.db.sql("""select * FROM `tabPrint Format` | frappe.response.docs.extend(frappe.db.sql("""select * FROM `tabPrint Format` | ||||
WHERE doc_type=%s AND docstatus<2""", (self.name,), as_dict=1, update={"doctype":"Print Format"})) | WHERE doc_type=%s AND docstatus<2""", (self.name,), as_dict=1, update={"doctype":"Print Format"})) | ||||
def load_workflows(self): | def load_workflows(self): | ||||
# get active workflow | # get active workflow | ||||
workflow_name = get_workflow_name(self.name) | workflow_name = get_workflow_name(self.name) | ||||
@@ -144,14 +144,13 @@ class FormMeta(Meta): | |||||
if workflow_name and frappe.db.exists("Workflow", workflow_name): | if workflow_name and frappe.db.exists("Workflow", workflow_name): | ||||
workflow = frappe.get_doc("Workflow", workflow_name) | workflow = frappe.get_doc("Workflow", workflow_name) | ||||
frappe.response.docs.append(workflow) | frappe.response.docs.append(workflow) | ||||
for d in workflow.get("workflow_document_states"): | for d in workflow.get("workflow_document_states"): | ||||
frappe.response.docs.append(frappe.get_doc("Workflow State", d.state)) | frappe.response.docs.append(frappe.get_doc("Workflow State", d.state)) | ||||
def render_jinja(content): | def render_jinja(content): | ||||
if "{% include" in content: | if "{% include" in content: | ||||
content = frappe.get_jenv().from_string(content).render() | content = frappe.get_jenv().from_string(content).render() | ||||
return content | return content | ||||