@@ -38,8 +38,11 @@ class _dict(dict): | |||
def copy(self): | |||
return _dict(dict(self).copy()) | |||
def _(msg): | |||
def _(msg, lang=None): | |||
"""Returns translated string in current lang, if exists.""" | |||
if not lang: | |||
lang = local.lang | |||
if local.lang == "en": | |||
return msg | |||
@@ -905,6 +908,20 @@ def get_all(doctype, *args, **kwargs): | |||
kwargs["limit_page_length"] = 0 | |||
return get_list(doctype, *args, **kwargs) | |||
def get_value(*args, **kwargs): | |||
"""Returns a document property or list of properties. | |||
Alias for `frappe.db.get_value` | |||
:param doctype: DocType name. | |||
:param filters: Filters like `{"x":"y"}` or name of the document. `None` if Single DocType. | |||
:param fieldname: Column name. | |||
:param ignore: Don't raise exception if table, column is missing. | |||
:param as_dict: Return values as dict. | |||
:param debug: Print query in error log. | |||
""" | |||
return db.get_value(*args, **kwargs) | |||
def add_version(doc): | |||
"""Insert a new **Version** of the given document. | |||
A **Version** is a JSON dump of the current document state.""" | |||
@@ -8,6 +8,29 @@ | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "file_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "File Name", | |||
"no_copy": 0, | |||
"oldfieldname": "file_name", | |||
"oldfieldtype": "Data", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
@@ -34,9 +57,10 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"depends_on": "", | |||
"fieldname": "is_home_folder", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"hidden": 1, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
@@ -52,6 +76,49 @@ | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"depends_on": "eval:!doc.is_folder", | |||
"fieldname": "file_url", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "File URL", | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"read_only": 1, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "column_break_5", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
@@ -79,16 +146,14 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "file_name", | |||
"fieldtype": "Data", | |||
"fieldname": "file_size", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "File Name", | |||
"in_list_view": 1, | |||
"label": "File Size", | |||
"no_copy": 0, | |||
"oldfieldname": "file_name", | |||
"oldfieldtype": "Data", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"read_only": 1, | |||
@@ -102,17 +167,17 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "file_url", | |||
"fieldtype": "Data", | |||
"fieldname": "section_break_8", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "File URL", | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"read_only": 1, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
@@ -145,20 +210,20 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "attached_to_name", | |||
"fieldtype": "Data", | |||
"fieldname": "column_break_10", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Attached To Name", | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"read_only": 1, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
@@ -166,20 +231,20 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "file_size", | |||
"fieldtype": "Int", | |||
"fieldname": "attached_to_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "File Size", | |||
"in_list_view": 0, | |||
"label": "Attached To Name", | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"read_only": 1, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"search_index": 1, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
@@ -275,12 +340,12 @@ | |||
"hide_toolbar": 0, | |||
"icon": "icon-file", | |||
"idx": 1, | |||
"in_create": 1, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"modified": "2015-09-02 06:17:57.856863", | |||
"modified": "2015-09-03 05:17:44.827959", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "File", | |||
@@ -21,6 +21,20 @@ class File(NestedSet): | |||
def before_insert(self): | |||
frappe.local.rollback_observers.append(self) | |||
self.set_folder_name() | |||
self.set_name() | |||
def set_name(self): | |||
"""Set name for folder""" | |||
if self.is_folder: | |||
if self.folder: | |||
path = get_breadcrumbs(self.folder) | |||
folder_name = frappe.get_value("File", self.folder, "file_name") | |||
self.name = "/".join([d.file_name for d in path] + [folder_name, self.file_name]) | |||
else: | |||
# home | |||
self.name = self.file_name | |||
else: | |||
self.name = self.file_url | |||
def after_insert(self): | |||
self.update_parent_folder_size() | |||
@@ -32,7 +46,7 @@ class File(NestedSet): | |||
def set_folder_size(self): | |||
"""Set folder size if folder""" | |||
if self.is_folder: | |||
if self.is_folder and not self.is_new(): | |||
self.fize_size = self.get_folder_size() | |||
for folder in self.get_ancestors(): | |||
@@ -45,33 +59,33 @@ class File(NestedSet): | |||
return frappe.db.sql("""select sum(ifnull(file_size,0)) | |||
from tabFile where folder=%s""", folder)[0][0] | |||
def update_parent_folder_size(self): | |||
"""Update size of parent folder""" | |||
if self.folder and not self.is_folder: # it not home | |||
frappe.get_doc("File", self.folder).save() | |||
def set_folder_name(self): | |||
"""Make parent folders if not exists based on reference doctype and name""" | |||
if self.attached_to_doctype and not self.folder: | |||
self.folder = self.get_parent_folder_name() | |||
def update_parent_folder_size(self): | |||
"""Update size of parent folder""" | |||
if self.folder: # it not home | |||
frappe.get_doc("File", self.folder).save() | |||
def get_parent_folder_name(self): | |||
"""Returns parent folder name. If not exists, then make""" | |||
doctype_folder_name = self.get_doctype_folder_name() | |||
parent_folder_name = frappe.db.get_value("File", {"file_name": self.attached_to_name, | |||
"is_folder": 1, "folder": doctype_folder_name}) | |||
return self.make_folder(parent_folder_name, doctype_folder_name, | |||
self.attached_to_name) | |||
def get_doctype_folder_name(self): | |||
"""Returns doctype folder name. If not exists, then make""" | |||
module_folder_name = self.get_module_folder_name() | |||
parent_folder_name = frappe.db.get_value("File", {"file_name": self.attached_to_doctype, | |||
doctype_folder_name = frappe.db.get_value("File", {"file_name": self.attached_to_doctype, | |||
"is_folder": 1, "folder": module_folder_name}) | |||
if not parent_folder_name: | |||
# parent folder | |||
parent_folder = frappe.get_doc({ | |||
"doctype": "File", | |||
"is_folder": 1, | |||
"file_name": _(self.attached_to_doctype), | |||
"folder": module_folder_name | |||
}).insert() | |||
parent_folder_name = parent_folder.name | |||
return parent_folder_name | |||
return self.make_folder(doctype_folder_name, module_folder_name, | |||
_(self.attached_to_doctype, frappe.db.get_default("lang"))) | |||
def get_module_folder_name(self): | |||
"""Returns module folder name. If not exists, then make""" | |||
@@ -83,18 +97,22 @@ class File(NestedSet): | |||
module_folder_name = frappe.db.get_value("File", {"file_name": module, | |||
"is_folder": 1, "folder": home_folder_name}) | |||
if not module_folder_name: | |||
module_folder = frappe.get_doc({ | |||
return self.make_folder(module_folder_name, home_folder_name, _(module, | |||
frappe.db.get_default("lang"))) | |||
def make_folder(self, name, folder, file_name): | |||
if not name: | |||
# parent folder | |||
file = frappe.get_doc({ | |||
"doctype": "File", | |||
"is_folder": 1, | |||
"file_name": _(module), | |||
"folder": home_folder_name | |||
"file_name": file_name, | |||
"folder": folder | |||
}).insert() | |||
module_folder_name = module_folder.name | |||
return module_folder_name | |||
name = file.name | |||
return name | |||
def validate_folder(self): | |||
if not self.is_home_folder and not self.folder and \ | |||
@@ -1,14 +1,7 @@ | |||
//TODO | |||
// show breadcrumbs | |||
// search bar to add search filter | |||
// back button | |||
// new | |||
// if file, attach | |||
// if folder, set name | |||
frappe.listview_settings['File'] = { | |||
hide_name_column: true, | |||
use_route: true, | |||
add_fields: ["is_folder", "file_name"], | |||
formatters: { | |||
file_size: function(value) { | |||
@@ -32,12 +25,23 @@ frappe.listview_settings['File'] = { | |||
} | |||
}, | |||
onload: function(doclist) { | |||
doclist.breadcrumb = $('<ol class="breadcrumb"></ol>') | |||
.insertBefore(doclist.wrapper.find(".show_filters")); | |||
doclist.filter_area = doclist.wrapper.find(".show_filters"); | |||
doclist.breadcrumb = $('<ol class="breadcrumb for-file-list"></ol>') | |||
.insertBefore(doclist.filter_area); | |||
}, | |||
before_run: function(doclist) { | |||
var name_filter = doclist.filter_list.get_filter("file_name"); | |||
if(name_filter) { | |||
doclist.filter_area.removeClass("hide"); | |||
doclist.breadcrumb.addClass("hide"); | |||
} else { | |||
doclist.filter_area.addClass("hide"); | |||
doclist.breadcrumb.removeClass("hide"); | |||
} | |||
}, | |||
refresh: function(doclist) { | |||
// set folder before querying | |||
var name_filter = doclist.filter_list.get_filter("name"); | |||
var name_filter = doclist.filter_list.get_filter("file_name"); | |||
var folder_filter = doclist.filter_list.get_filter("folder"); | |||
if(folder_filter) { | |||
@@ -46,6 +50,12 @@ frappe.listview_settings['File'] = { | |||
if(name_filter) return; | |||
var route = frappe.get_route(); | |||
if(route[2]) { | |||
doclist.current_folder = route.slice(2).join("/"); | |||
doclist.current_folder_name = route.slice(-1)[0]; | |||
} | |||
if(!doclist.current_folder) { | |||
doclist.current_folder = frappe.boot.home_folder; | |||
doclist.current_folder_name = __("Home"); | |||
@@ -58,14 +68,12 @@ frappe.listview_settings['File'] = { | |||
}, | |||
post_render_item: function(list, row, data) { | |||
if(data.is_folder) { | |||
$(row).find(".list-id").on("click", function() { | |||
list.doclistview.current_folder = data.name; | |||
list.doclistview.current_folder_name = data.file_name; | |||
list.doclistview.refresh(); | |||
return false; | |||
}); | |||
$(row).find(".list-id").attr("href", "#List/File/" + data.name); | |||
} | |||
}, | |||
set_file_route: function(name) { | |||
frappe.set_route(["List", "File"].concat(decodeURIComponent(name).split("/"))); | |||
}, | |||
post_render: function(doclist) { | |||
frappe.call({ | |||
method: "frappe.core.doctype.file.file.get_breadcrumbs", | |||
@@ -76,16 +84,9 @@ frappe.listview_settings['File'] = { | |||
doclist.breadcrumb.empty(); | |||
if(r.message && r.message.length) { | |||
$.each(r.message, function(i, folder) { | |||
$('<li><a href="#">'+ folder.file_name+'</a></li>') | |||
.appendTo(doclist.breadcrumb) | |||
.attr("name", folder.name) | |||
.attr("file_name", folder.file_name) | |||
.on("click", function() { | |||
doclist.current_folder = $(this).attr("name"); | |||
doclist.current_folder_name = $(this).attr("file_name"); | |||
doclist.refresh(); | |||
return false; | |||
}); | |||
$('<li><a href="#List/File/'+folder.name+'">' | |||
+ folder.file_name+'</a></li>') | |||
.appendTo(doclist.breadcrumb); | |||
}); | |||
} | |||
$('<li class="active">'+ doclist.current_folder_name+'</li>') | |||
@@ -200,11 +200,11 @@ CREATE TABLE `__Auth` ( | |||
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8mb4 COLLATE=utf8mb4_unicode_ci; | |||
-- | |||
-- Table structure for table `tabFile` | |||
-- | |||
DROP TABLE IF EXISTS `tabFile Data`; | |||
CREATE TABLE `tabFile Data` ( | |||
DROP TABLE IF EXISTS `tabFile`; | |||
CREATE TABLE `tabFile` ( | |||
`name` varchar(255) NOT NULL, | |||
`creation` datetime(6) DEFAULT NULL, | |||
`modified` datetime(6) DEFAULT NULL, | |||
@@ -59,14 +59,18 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0, | |||
# build from doctype | |||
if txt: | |||
search_fields = ["name"] | |||
if meta.title_field: | |||
search_fields.append(meta.title_field) | |||
if meta.search_fields: | |||
for f in meta.get_search_fields(): | |||
fmeta = meta.get_field(f.strip()) | |||
if f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text", | |||
"Link", "Select", "Read Only", "Text Editor"]): | |||
or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)]) | |||
else: | |||
filters.append([doctype, searchfield or "name", "like", "%{0}%".format(txt)]) | |||
search_fields.extend(meta.get_search_fields()) | |||
for f in search_fields: | |||
fmeta = meta.get_field(f.strip()) | |||
if f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text", | |||
"Link", "Select", "Read Only", "Text Editor"]): | |||
or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)]) | |||
if meta.get("fields", {"fieldname":"enabled", "fieldtype":"Check"}): | |||
filters.append([doctype, "enabled", "=", 1]) | |||
@@ -86,6 +86,10 @@ class Document(BaseDocument): | |||
self._default_new_docs = {} | |||
self.flags = frappe._dict() | |||
def reload(self): | |||
"""Reload document from database""" | |||
self.load_from_db() | |||
def load_from_db(self): | |||
"""Load document and children from database and create properties | |||
from fields""" | |||
@@ -7,6 +7,10 @@ def execute(): | |||
frappe.rename_doc("DocType", "File Data", "File") | |||
frappe.reload_doctype("File") | |||
# DELETE THIS | |||
frappe.db.sql("""delete from tabFile where is_folder=1""") | |||
frappe.db.sql("""update tabFile set folder=null""") | |||
if not frappe.db.exists("File", {"is_home_folder": 1}): | |||
make_home_folder() | |||
@@ -14,6 +18,7 @@ def execute(): | |||
for file in frappe.get_all("File", filters={"is_folder": 0}): | |||
file = frappe.get_doc("File", file.name) | |||
file.flags.ignore_folder_validate = True | |||
file.set_folder_name() | |||
file.save() | |||
from frappe.utils.nestedset import rebuild_tree | |||
@@ -22,8 +27,6 @@ def execute(): | |||
# reset file size | |||
for folder in frappe.db.sql("""select name from tabFile f1 where is_folder = 1 and | |||
(select count(*) from tabFile f2 where f2.folder = f1.name and f2.is_folder = 1) = 0"""): | |||
print folder[0] | |||
folder = frappe.get_doc("File", folder[0]) | |||
folder.save() | |||
@@ -523,5 +523,10 @@ ul.linked-with-list li { | |||
} | |||
.breadcrumb { | |||
font-size: 12px; | |||
margin-bottom: 10px; | |||
background-color: #fff; | |||
} | |||
.breadcrumb.for-file-list { | |||
margin-bottom: 0px; | |||
border-bottom: 1px solid #d1d8dd; | |||
border-radius: 0px; | |||
} |
@@ -14,10 +14,14 @@ frappe.views.ListFactory = frappe.views.Factory.extend({ | |||
if(locals["DocType"][doctype].issingle) { | |||
frappe.set_re_route("Form", doctype); | |||
} else { | |||
new frappe.views.DocListView({ | |||
doctype: doctype, | |||
parent: me.make_page(true) | |||
}); | |||
if(!frappe.views.doclistview[doctype]) { | |||
frappe.views.doclistview[doctype] = new frappe.views.DocListView({ | |||
doctype: doctype, | |||
parent: me.make_page(true, "List/" + doctype) | |||
}); | |||
} else { | |||
frappe.container.change_to(frappe.views.doclistview[doctype].page_name); | |||
} | |||
me.set_cur_list(); | |||
} | |||
}); | |||
@@ -65,6 +69,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||
}; | |||
this.label = __(this.doctype); | |||
this.page_name = "List/" + this.doctype; | |||
this.dirty = true; | |||
this.tags_shown = false; | |||
this.label = (this.label.toLowerCase().substr(-4) == 'list') ? | |||
@@ -236,6 +241,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||
if(frappe.route_options) { | |||
me.set_route_options(); | |||
me.run(); | |||
} else if(me.dirty) { | |||
me.run(); | |||
} else { | |||
@@ -265,17 +271,22 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||
} | |||
}); | |||
frappe.route_options = null; | |||
me.run(); | |||
}, | |||
run: function(more) { | |||
// set filter from route | |||
var route = frappe.get_route(); | |||
var me = this; | |||
if(route[2]) { | |||
$.each(frappe.utils.get_args_dict_from_url(route[2]), function(key, val) { | |||
me.set_filter(key, val, true); | |||
}); | |||
if(this.listview.settings.before_run) { | |||
this.listview.settings.before_run(this); | |||
} | |||
if(!this.listview.settings.use_route) { | |||
var route = frappe.get_route(); | |||
var me = this; | |||
if(route[2]) { | |||
$.each(frappe.utils.get_args_dict_from_url(route[2]), function(key, val) { | |||
me.set_filter(key, val, true); | |||
}); | |||
} | |||
} | |||
this.list_header.find(".list-starred-by-me") | |||
@@ -182,7 +182,7 @@ frappe.ui.Filter = Class.extend({ | |||
if(!dont_run) { | |||
this.flist.listobj.dirty = true; | |||
this.flist.listobj.run(); | |||
this.flist.listobj.refresh(); | |||
} | |||
}, | |||
@@ -145,7 +145,7 @@ frappe.search.verbs = [ | |||
value: __('Find {0} in {1}', [txt, route[1]]), | |||
route_options: options, | |||
onclick: function() { | |||
frappe.container.page.doclistview.set_route_options(); | |||
cur_list.refresh(); | |||
}, | |||
match: txt | |||
}); | |||
@@ -13,7 +13,9 @@ frappe.views.Factory = Class.extend({ | |||
me = this; | |||
if(frappe.pages[page_name] && page_name.indexOf("Form/")===-1) { | |||
frappe.container.change_to(frappe.pages[page_name]); | |||
if(me.on_show) me.on_show(); | |||
if(me.on_show) { | |||
me.on_show(); | |||
} | |||
} else { | |||
var route = frappe.get_route(); | |||
if(route[1]) { | |||
@@ -23,14 +25,16 @@ frappe.views.Factory = Class.extend({ | |||
} | |||
} | |||
}, | |||
make_page: function(double_column) { | |||
return frappe.make_page(double_column); | |||
make_page: function(double_column, page_name) { | |||
return frappe.make_page(double_column, page_name); | |||
} | |||
}); | |||
frappe.make_page = function(double_column) { | |||
var page_name = frappe.get_route_str(), | |||
page = frappe.container.add_page(page_name); | |||
frappe.make_page = function(double_column, page_name) { | |||
if(!page_name) { | |||
var page_name = frappe.get_route_str(); | |||
} | |||
var page = frappe.container.add_page(page_name); | |||
frappe.ui.make_app_page({ | |||
parent: page, | |||
@@ -380,5 +380,11 @@ ul.linked-with-list li { | |||
.breadcrumb { | |||
font-size: 12px; | |||
margin-bottom: 10px; | |||
background-color: #fff; | |||
} | |||
.breadcrumb.for-file-list { | |||
margin-bottom: 0px; | |||
border-bottom: 1px solid @border-color; | |||
border-radius: 0px; | |||
} |
@@ -39,6 +39,9 @@ def after_install(): | |||
{'doctype': "Email Account", "email_id": "replies@example.com", "default_incoming": 1} | |||
] | |||
from frappe.core.doctype.file.file import make_home_folder | |||
make_home_folder() | |||
for d in install_docs: | |||
try: | |||
frappe.get_doc(d).insert() | |||