diff --git a/frappe/model/meta.py b/frappe/model/meta.py
index f4f2c099a8..6a5d001202 100644
--- a/frappe/model/meta.py
+++ b/frappe/model/meta.py
@@ -99,6 +99,18 @@ class Meta(Document):
def get_options(self, fieldname):
return self.get_field(fieldname).options
+ def get_search_fields(self):
+ search_fields = self.search_fields or "name"
+ search_fields = [d.strip() for d in search_fields.split(",")]
+ if "name" not in search_fields:
+ search_fields.append("name")
+
+ return search_fields
+
+ def get_list_fields(self):
+ return ["name"] + [d.fieldname \
+ for d in self.fields if (d.in_list_view and d.fieldtype in type_map)]
+
def process(self):
# don't process for special doctypes
# prevent's circular dependency
@@ -203,7 +215,7 @@ doctype_table_fields = [
def is_single(doctype):
try:
return frappe.db.get_value("DocType", doctype, "issingle")
- except IndexError, e:
+ except IndexError:
raise Exception, 'Cannot determine whether %s is single' % doctype
def get_parent_dt(dt):
diff --git a/frappe/templates/pages/list.html b/frappe/templates/pages/list.html
new file mode 100644
index 0000000000..11a5b15512
--- /dev/null
+++ b/frappe/templates/pages/list.html
@@ -0,0 +1,84 @@
+{% block title %}{{ type }} {{ _("List") }}{% endblock %}
+
+{% block header %}
+
{{ type }} {{ _("List") }}
+{% endblock %}
+
+{% block content %}
+
+
+
+{% if txt %}
+Results filtered by
{{ txt }} .
×
+{% endif %}
+
+{% for item in items %}
+
+ {{ item }}
+
+{% endfor %}
+
+
+ More
+
+{% endblock %}
+
+{% block script %}
+
+{% endblock %}
diff --git a/frappe/templates/pages/list.py b/frappe/templates/pages/list.py
new file mode 100644
index 0000000000..92a10c3421
--- /dev/null
+++ b/frappe/templates/pages/list.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe, os
+from frappe.modules import get_doc_path
+from jinja2 import Environment, Template, FileSystemLoader
+
+no_cache = 1
+no_sitemap = 1
+
+def get_context(context):
+ context.type = frappe.local.form_dict.type
+ context.txt = frappe.local.form_dict.txt
+ context.update(get_items(context.type, context.txt))
+ return context
+
+@frappe.whitelist(allow_guest=True)
+def get_items(type, txt, limit_start=0):
+ meta = frappe.get_meta(type)
+ filters, or_filters = [], []
+ out = frappe._dict()
+
+ if txt:
+ if meta.search_fields:
+ for f in meta.get_search_fields():
+ or_filters.append([type, f.strip(), "like", "%" + txt + "%"])
+ else:
+ filters.append([type, "name", "like", "%" + txt + "%"])
+
+
+ out.raw_items = frappe.get_list(type, fields = meta.get_list_fields(),
+ filters=filters, or_filters = or_filters, limit_start=limit_start,
+ limit_page_length = 20)
+ template_path = os.path.join(get_doc_path(meta.module, "DocType", meta.name), "list_item.html")
+
+ if os.path.exists(template_path):
+ env = Environment(loader = FileSystemLoader("."))
+ template = env.get_template(template_path)
+ else:
+ template = Template("""""")
+
+ out.items = [template.render(item=i, doctype=type) for i in out.raw_items]
+
+ return out
diff --git a/frappe/templates/pages/message.html b/frappe/templates/pages/message.html
index df8f6ac7af..2c70bf8457 100644
--- a/frappe/templates/pages/message.html
+++ b/frappe/templates/pages/message.html
@@ -7,4 +7,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/frappe/templates/pages/view.html b/frappe/templates/pages/view.html
new file mode 100644
index 0000000000..699e1b12e8
--- /dev/null
+++ b/frappe/templates/pages/view.html
@@ -0,0 +1,40 @@
+{% block title %}{{ doc.doctype }} / {{ doc.name }}{% endblock %}
+
+{% block header %}
+{{ doc.name }}
+{{ doc.doctype }}
+{% endblock %}
+
+{% block content %}
+{% if custom_view %}
+{{ custom_view }}
+{% else %}
+{% for df in meta.fields %}
+ {% if not df.hidden and not df.permlevel and not df.print_hide %}
+ {% if df.fieldtype=="Section Break" %}
+
{{ df.label or "" }}
+ {% elif df.fieldtype=="Column Break" %}
+ {% elif df.fieldtype=="Table" %}
+
+ {% else %}
+
+
+ {% if df.fieldtype not in ("Image",) %}
+ {{ df.label }}
+ {% endif %}
+
+
+ {% if df.fieldtype=="Check" %}
+
+ {% elif df.fieldtype=="Image" %}
+
+ {% else %}
+ {{ doc[df.fieldname] }}
+ {% endif %}
+
+
+ {% endif %}
+ {% endif %}
+{% endfor %}
+{% endif %}
+{% endblock %}
diff --git a/frappe/templates/pages/view.py b/frappe/templates/pages/view.py
new file mode 100644
index 0000000000..e6f31d3146
--- /dev/null
+++ b/frappe/templates/pages/view.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+no_cache = 1
+no_sitemap = 1
+
+def get_context(context):
+ return {
+ "doc": frappe.get_doc(frappe.local.form_dict.doctype, frappe.local.form_dict.name),
+ "meta": frappe.get_meta(frappe.local.form_dict.doctype)
+ }
diff --git a/frappe/website/js/website.js b/frappe/website/js/website.js
index fba7a35934..ee399ca7e0 100644
--- a/frappe/website/js/website.js
+++ b/frappe/website/js/website.js
@@ -221,6 +221,9 @@ $.extend(frappe, {
if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey )
return;
+ if (link.getAttribute("target"))
+ return;
+
// Ignore cross origin links
if ( location.protocol !== link.protocol || location.hostname !== link.hostname )
return;
diff --git a/frappe/website/render.py b/frappe/website/render.py
index c512eb1768..ef16616bfe 100644
--- a/frappe/website/render.py
+++ b/frappe/website/render.py
@@ -8,7 +8,7 @@ from werkzeug.wrappers import Response
from frappe.website.context import get_context
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache
-from frappe.website.permissions import get_access, clear_permissions
+from frappe.website.permissions import clear_permissions
class PageNotFoundError(Exception): pass
@@ -18,9 +18,25 @@ def render(path, http_status_code=None):
try:
data = render_page(path)
-
except frappe.DoesNotExistError, e:
- path = "404"
+ doctype, name = get_doctype_from_path(path)
+ if doctype and name:
+ path = "view"
+ frappe.local.form_dict.doctype = doctype
+ frappe.local.form_dict.name = name
+ elif doctype:
+ path = "list"
+ frappe.local.form_dict.type = doctype
+ else:
+ path = "404"
+ http_status_code = e.http_status_code
+
+ data = render_page(path)
+
+ except frappe.PermissionError, e:
+ path = "message"
+ frappe.local.message = "Did you log out?"
+ frappe.local.message_title = "Not Permitted"
data = render_page(path)
http_status_code = e.http_status_code
@@ -31,6 +47,24 @@ def render(path, http_status_code=None):
return build_response(path, data, http_status_code or 200)
+def get_doctype_from_path(path):
+ doctypes = [d[0] for d in frappe.get_list("DocType", as_list=True)]
+
+ parts = path.split("/")
+
+ doctype = parts[0]
+ name = parts[1] if len(parts) > 1 else None
+
+ if doctype in doctypes:
+ return doctype, name
+
+ # try scrubbed
+ doctype = doctype.replace("_", " ").title()
+ if doctype in doctypes:
+ return doctype, name
+
+ return None, None
+
def build_response(path, data, http_status_code):
# build response
response = Response()
diff --git a/frappe/widgets/search.py b/frappe/widgets/search.py
index 3a4200d7dd..537e263868 100644
--- a/frappe/widgets/search.py
+++ b/frappe/widgets/search.py
@@ -61,7 +61,7 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
# build from doctype
if txt:
if meta.search_fields:
- for f in meta.search_fields.split(","):
+ for f in meta.get_search_fields():
or_filters.append([doctype, f.strip(), "like", "%" + txt + "%"])
else:
filters.append([doctype, searchfield or "name", "like",