diff --git a/core/doctype/documentation_tool/__init__.py b/core/doctype/documentation_tool/__init__.py deleted file mode 100644 index cebc5adf82..0000000000 --- a/core/doctype/documentation_tool/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - diff --git a/core/doctype/documentation_tool/docs.css b/core/doctype/documentation_tool/docs.css deleted file mode 100644 index add040b063..0000000000 --- a/core/doctype/documentation_tool/docs.css +++ /dev/null @@ -1,77 +0,0 @@ -@import url(http://fonts.googleapis.com/css?family=Noticia+Text); -@import url(http://fonts.googleapis.com/css?family=Open+Sans); - -body { - font-family: "Noticia Text", Serif; - font-size: 16px; - text-rendering: optimizeLegibility; - color: #222; - line-height: 1.8; -} - -h1, h2, h3, h4, .navbar { - font-family: "Open Sans", Sans-Serif; -} - -h1, h2, h3, h4, h5 { - font-weight: bold; -} - -img { - max-width: 100%; -} - -.container { - max-width: 767px; -} - -.navbar { - background-color: #ffffff; - border-bottom: 5px solid #c0392b; - border-radius: 0px; -} - -.navbar .navbar-nav > li > a:hover -{ - color: #444444; -} - -h1, h2, h3 { - font-weight: bold; -} - - .logo { - font-weight: bold; -} - -li { - line-height: inherit; -} - -.content img { - border-radius: 5px; -} - -blockquote { - padding: 10px 0 10px 15px; - margin: 0 0 20px; - background-color: #FFFCED; - border-left: 5px solid #fbeed5; -} - -blockquote p { - margin-bottom: 0; - font-size: 16px; - font-weight: normal; - line-height: 25px; -} - -.erpnext-logo { - width: 32px; - height: 32px; - margin: -11px 0px; -} - -.erpnext-logo rect { - fill: #ffffff !important; -} \ No newline at end of file diff --git a/core/doctype/documentation_tool/docs.html b/core/doctype/documentation_tool/docs.html deleted file mode 100644 index 22d91e9137..0000000000 --- a/core/doctype/documentation_tool/docs.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - {{ title }} - - - - - - - - - - - -
- {% block navbar %}{% endblock %} -
-
-
-
- {%- if not _no_title %} -

-

{{ _label }}

- - {%- if _toc_links and not _no_toc %} - -
-

Contents

-
    - {%- for t in _toc_links %} -
  1. {{ t.label }}
  2. - {% endfor -%} -
-
- - {%- endif -%} - {% endif -%} - {{ content }} -
- -

- {% if _gh_source -%} - Source - {%- endif -%} - {% if _modified -%} - {%- if _gh_source %} | {% endif -%} - Last Updated: {{ _modified }} - {%- endif %} -

-
- - {%- if _parent_title -%} -
- - {{ _parent_title }} - {% if _next_title -%} - - {{ _next_title }} - {%- endif -%} - {% if _child_title -%} - - {{ _child_title }} - {%- endif -%} -
- {%- endif -%} - -
-
-
- {% block footer %}{% endblock %} -

 

-
- - - - diff --git a/core/doctype/documentation_tool/documentation_tool.js b/core/doctype/documentation_tool/documentation_tool.js deleted file mode 100644 index b3ea721b5c..0000000000 --- a/core/doctype/documentation_tool/documentation_tool.js +++ /dev/null @@ -1,539 +0,0 @@ -wn.require("lib/public/js/lib/beautify-html.js"); - -cur_frm.cscript.onload = function(doc) { - wn.docs.build_client_app_toc(wn, "wn"); -} - -cur_frm.cscript.refresh = function(doc) { - cur_frm.disable_save(); - - cur_frm.add_custom_button("Make Docs", function() { - wn.model.with_doctype("DocType", function() { - wn.docs.generate_all($(cur_frm.fields_dict.out.wrapper)); - }) - }); -} - -wn.provide("docs"); -wn.provide("wn.docs"); - -wn.docs.generate_all = function(logarea) { - wn.docs.to_write = {}; - var pages = [], - body = $("
"), - original_cur_frm = cur_frm; - doc = cur_frm.doc; - make_page = function(name, links) { - body.empty(); - var page = new wn.docs.DocsPage({ - namespace: name, - parent: body, - links: links - }); - - var for_namespace = ( - doc.build_pages ? doc.page_name : - (doc.build_modules ? null : ( - doc.build_server_api ? doc.python_module_name : null))); - - page.write(for_namespace); - - // make_page for _toc items - var pages = (page.obj._toc || []).concat(page.obj._links || []); - if(pages && pages.length) { - $.each(pages, function(i, child_name) { - var parent_name = child_name.split(".").slice(0,-1).join("."), - child_links = { - parent: parent_name - } - parentobj = wn.provide(parent_name); - - if(parentobj._toc) { - $.each(parentobj._toc, function(j, sibling) { - if(sibling===child_name && j!==parentobj._toc.length-1) - child_links.next_sibling = parentobj._toc[i+1]; - }) - } - var docs_full_name = wn.docs.get_full_name(child_name); - if(!wn.docs.to_write[docs_full_name]) { - make_page(docs_full_name, child_links); - } - }); - } - } - - logarea.empty().append("Downloading server docs...
"); - - return wn.call({ - "method": "core.doctype.documentation_tool.documentation_tool.get_docs", - args: {options: cur_frm.doc}, - callback: function(r) { - - // append - wn.provide("docs.dev").modules = r.message.modules; - wn.provide("docs.dev.framework.server").webnotes = r.message.webnotes; - wn.provide("docs.dev.framework.client").wn = wn; - - if(!docs._links) docs._links = []; - - // append static pages to the "docs" object - $.each(r.message.pages || [], function(n, obj) { - $.extend(wn.provide(n), obj); - }); - - logarea.append("Preparing html...
"); - - make_page("docs"); - - logarea.append("Writing...
"); - return wn.call({ - method: "core.doctype.documentation_tool.documentation_tool.write_docs", - args: { - data: JSON.stringify(wn.docs.to_write), - build_sitemap: doc.build_sitemap, - domain: doc.sitemap_domain - }, - callback: function(r) { - logarea.append("Wrote " + keys(wn.docs.to_write).length + " pages."); - cur_frm = original_cur_frm; - } - }); - } - }); -} - -wn.docs.build_client_app_toc = function(obj, obj_name) { - var is_module = function(value) { - return value - && $.isPlainObject(value) - && value._type !== "instance" - && has_function_or_class(value) - } - var has_function_or_class = function(value) { - var ret = false; - $.each(value, function(name, prop) { - if(prop && - (typeof prop === "function" - || prop._type === "class") - && prop._type !== "instance") { - ret = true; - return false; - } - }) - return ret - } - if($.isPlainObject(obj)) { - var toc = []; - $.each(obj, function(name, value) { - if(value) { - if(is_module(value) || value._type==="class") - toc.push(obj_name + "." + name); - } - }); - if(toc.length) { - obj._toc = toc; - $.each(toc, function(i, full_name) { - var name = full_name.split(".").slice(-1)[0]; - wn.docs.build_client_app_toc(obj[name], full_name); - }) - } - } -} - -wn.docs.get_full_name = function(name) { - /* docs: - Get full name with docs namespace - */ - var link_name = name; - if(name.substr(0,2)==="wn") { - link_name = "docs.dev.framework.client." + name; - } - if(name.substr(0,8)==="webnotes") { - link_name = "docs.dev.framework.server." + name; - } - return link_name; -} - -wn.docs.get_short_name = function(namespace) { - namespace = namespace.replace("docs.dev.framework.server.", "") - namespace = namespace.replace("docs.dev.framework.client.", "") - return namespace; -} - -wn.docs.get_title = function(namespace) { - var obj = wn.provide(namespace); - return obj._label || wn.docs.get_short_name(namespace) -} - -wn.docs.DocsPage = Class.extend({ - init: function(opts) { - /* docs: create js documentation */ - $.extend(this, opts); - - var obj = wn.provide(this.namespace), - me = this; - - obj = (obj._type == "class" && obj.prototype) ? obj.prototype : obj; - if(obj._toc && this.links) - this.links.first_child = obj._toc[0]; - - this.obj = obj; - this.make(obj); - }, - make: function(obj) { - var has_docs = false; - this.make_title(obj); - this.make_breadcrumbs(obj); - has_docs = this.make_intro(obj); - has_docs = this.make_toc(obj) || has_docs; - if(obj._type==="model") { - this.make_docproperties(obj); - this.make_docfields(obj); - has_docs = true; - } - if(obj._type=="permissions") { - this.make_docperms(obj); - has_docs = true; - } - if(obj._type==="controller_client") { - try { - this.make_obj_from_cur_frm(obj); - } catch(e) { - console.log("Failed: " + obj._label); - console.log(e); - } - } - - has_docs = this.make_functions(obj) || has_docs; - - if(!has_docs) { - $('

No docs

').appendTo(this.parent); - } - - if(this.links) { - this.make_links(); - } - }, - make_links: function() { - if(this.links.parent) { - this.obj._parent_title = wn.docs.get_title(this.links.parent); - this.obj._parent_page = wn.docs.get_full_name(this.links.parent) + ".html"; - - - if(this.links.next_sibling) { - this.obj._next_title = wn.docs.get_title(this.links.next_sibling); - this.obj._next_page = wn.docs.get_full_name(this.links.next_sibling) + ".html"; - } - - if (this.links.first_child) { - this.obj._child_title = wn.docs.get_title(this.links.first_child); - this.obj._child_page = wn.docs.get_full_name(this.links.first_child) + ".html"; - } - } - }, - make_title: function(obj) { - if(!obj._no_title) { - var page_icon = obj._icon; - if(!obj._icon) { - if(this.namespace.indexOf(".wn.")!==-1) - obj._icon = "code"; - else - obj._icon = "file-text-alt"; - } - - if(!obj._label) obj._label = wn.docs.get_short_name(this.namespace) - } - }, - make_breadcrumbs: function(obj) { - var me = this, - name = this.namespace - - if(name==="docs") return; - - obj._breadcrumbs = []; - - var parts = name.split("."), - fullname = ""; - - $.each(parts, function(i, p) { - if(i!=parts.length-1) { - fullname = fullname + (fullname ? "." : "") + p; - - obj._breadcrumbs.push({ - link: (fullname==="docs" ? "index" : fullname) + ".html", - label: wn.provide(fullname)._label || p - }) - } - }); - }, - make_intro: function(obj) { - if(obj._intro) { - $("

").html(wn.markdown(obj._intro)).appendTo(this.parent); - return true; - } - }, - make_toc: function(obj) { - if(obj._toc && !obj._no_toc) { - obj._toc_links = []; - $.each(obj._toc, function(i, name) { - var link_name = wn.docs.get_full_name(name); - obj._toc_links.push({ - link: link_name + ".html", - label: wn.provide(link_name)._label || name - }); - }); - return true; - } - }, - - make_docproperties: function(obj) { - var me = this; - - this.h3("Properties"); - var tbody = this.get_tbody([ - {label:"Property", width: "25%"}, - {label:"Value", width: "25%"}, - {label:"Description", width: "50%"}, - ]); - - $.each(wn.model.get("DocField", {parent:"DocType"}), function(i, df) { - if(wn.model.no_value_type.indexOf(df.fieldtype)===-1) { - if(!df.description) - df.description = ""; - df.value = obj._properties[df.fieldname]==null || ""; - if(df.value!=="") { - $(repl('\ - %(label)s\ - %(value)s\ - %(description)s\ - ', df)).appendTo(tbody); - } - } - }); - }, - - make_docfields: function(obj) { - var me = this, - docfields = obj._fields; - - if(docfields.length) { - this.h3("DocFields"); - var tbody = this.get_tbody([ - {label:"Sr", width: "10%"}, - {label:"Fieldname", width: "25%"}, - {label:"Label", width: "20%"}, - {label:"Field Type", width: "25%"}, - {label:"Options", width: "20%"}, - ]); - docfields = docfields.sort(function(a, b) { return a.idx > b.idx ? 1 : -1 }) - $.each(docfields, function(i, df) { - $(repl('\ - %(idx)s\ - %(fieldname)s\ - %(label)s\ - %(fieldtype)s\ - %(options)s\ - ', df)).appendTo(tbody); - }); - }; - }, - make_docperms: function(obj) { - var me = this; - if(obj._permissions.length) { - this.h3("Permissions"); - var tbody = this.get_tbody([ - {label:"Sr", width: "8%"}, - {label:"Role", width: "20%"}, - {label:"Level", width: "7%"}, - {label:"Read", width: "7%"}, - {label:"Write", width: "8%"}, - {label:"Create", width: "8%"}, - {label:"Submit", width: "8%"}, - {label:"Cancel", width: "8%"}, - {label:"Amend", width: "8%"}, - {label:"Report", width: "8%"}, - {label:"Match", width: "10%"}, - ]); - obj._permissions = obj._permissions.sort(function(a, b) { - return a.idx > b.idx ? 1 : -1 - }) - $.each(obj._permissions, function(i, perm) { - if(!perm.match) perm.match = ""; - $.each(["permlevel", "read", "write", "cancel", "create", "submit", - "amend", "report", "match"], function(i, key) { - if(perm[key]==null) perm[key] = ""; - }); - $(repl('\ - %(idx)s\ - %(role)s\ - %(permlevel)s\ - %(read)s\ - %(write)s\ - %(create)s\ - %(submit)s\ - %(cancel)s\ - %(amend)s\ - %(report)s\ - %(match)s\ - ', perm)).appendTo(tbody); - }); - }; - }, - make_obj_from_cur_frm: function(obj) { - var me = this; - obj._fetches = []; - cur_frm = { - set_query: function() { - - }, - cscript: {}, - pformat: {}, - add_fetch: function() { - obj._fetches.push(arguments) - }, - fields_dict: {}, - call: function() { - - } - }; - $.each(obj._fields, function(i, f) { - cur_frm.fields_dict[f] = { - grid: { - get_field: function(fieldname) { - return {} - } - } - }} - ); - var tmp = eval(obj._code); - $.extend(obj, cur_frm.cscript); - }, - make_functions: function(obj) { - var functions = this.get_functions(obj); - if(!$.isEmptyObject(functions)) { - this.h3(obj._type === "class" ? "Methods" : "Functions"); - this.make_function_table(functions); - return true; - } - }, - get_functions: function(obj) { - var functions = {}; - - $.each(obj || {}, function(name, value) { - if(value && ((typeof value==="function" && typeof value.init !== "function") - || value._type === "function")) - functions[name] = value; - }); - return functions; - }, - make_function_table: function(functions, namespace) { - var me = this, - tbody = this.get_tbody(); - - $.each(functions || {}, function(name, value) { - me.render_function(name, value, tbody, namespace) - }); - }, - get_tbody: function(columns) { - table = $("\ - \ - \ -
").appendTo(this.parent); - if(columns) { - $.each(columns || [], function(i, c) { - $("") - .css({"width": c.width}) - .html(c.label) - .appendTo(table.find("thead")) - }); - } - return table.find("tbody"); - }, - h3: function(txt) { - $("

").html(txt).appendTo(this.parent); - }, - render_function: function(name, value, parent, namespace) { - var me = this, - code = value.toString(); - - namespace = namespace===undefined ? - ((this.obj._type==="class" || this.obj._type==="controller_client") ? - "" : this.namespace) - : ""; - - if(this.obj._function_namespace) - namespace = this.obj._function_namespace; - - if(namespace!=="") { - namespace = wn.docs.get_short_name(namespace); - } - - if(namespace!=="" && namespace[namespace.length-1]!==".") - namespace = namespace + "."; - - var args = this.get_args(value); - - var help = value._help || code.split("/* docs:")[1]; - if(help && help.indexOf("*/")!==-1) help = help.split("*/")[0]; - - var source = ""; - if(code.substr(0, 8)==="function" || value._source) { - source = repl('

\ - View Source

\ -
\
-%(code)s
', { - name: name, - code: value._source || code, - lang: (value._source ? "python" : "javascript") - }); - } - - try { - $(repl('\ - %(name)s\ - \ -

Usage:
\ -
%(namespace)s%(name)s(%(args)s)
\ - %(help)s\ - %(source)s\ - \ - ', { - name: name, - namespace: namespace, - args: args, - help: help ? wn.markdown(help) : "", - source: source - })).appendTo(parent) - } catch(e) { - console.log("Possible html embedded in: " + name) - console.log(e); - } - }, - get_args: function(obj) { - if(obj._args) - return obj._args.join(", "); - else - return obj.toString().split("function")[1].split("(")[1].split(")")[0]; - }, - write: function(callback, for_namespace) { - var me = this; - if(for_namespace && for_namespace!==this.namespace) { - callback(); - return; - } - - var args = {}; - $.each(["_label", "_gh_source", "_modified", "_parent_title", "_parent_page", - "_next_title", "_next_page", "_child_title", "_child_page", "_no_title", - "_breadcrumbs", "_toc_links"], function(i, key) { - if(me.obj[key]) - args[key] = me.obj[key] - }) - - args.content = html_beautify(this.parent.html()) - - wn.docs.to_write[this.namespace] = args; - } -}) \ No newline at end of file diff --git a/core/doctype/documentation_tool/documentation_tool.py b/core/doctype/documentation_tool/documentation_tool.py deleted file mode 100644 index cc2db032e7..0000000000 --- a/core/doctype/documentation_tool/documentation_tool.py +++ /dev/null @@ -1,520 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - -# For license information, please see license.txt - -from __future__ import unicode_literals - -import webnotes -import inspect, os, json, datetime, shutil -from webnotes.modules import get_doc_path, get_module_path, scrub -from webnotes.utils import get_path, get_base_path, cstr - -class DocType: - def __init__(self, d, dl): - self.doc, self.doclist = d, dl - - def onload(self): - prepare_docs() - -gh_prefix = "https://github.com/webnotes/" - -@webnotes.whitelist() -def get_docs(options): - docs = {} - options = webnotes._dict(json.loads(options)) - if options.build_server_api: - get_docs_for(docs, "webnotes") - if options.build_modules: - docs["modules"] = get_modules(options.module_name) - if options.build_pages: - docs["pages"] = get_static_pages() - return docs - -def get_static_pages(): - mydocs = {} - for repo in ("lib", "app"): - for basepath, folders, files in os.walk(get_path(repo, "docs")): - for fname in files: - fname = cstr(fname) - if fname.endswith(".md"): - fpath = get_path(basepath, fname) - with open(fpath, "r") as docfile: - src = unicode(docfile.read(), "utf-8") - try: - temp, headers, body = src.split("---", 2) - d = json.loads(headers) - except Exception, e: - webnotes.msgprint("Bad Headers in: " + fname) - continue - d["_intro"] = body - d["_gh_source"] = get_gh_url(fpath) - d["_modified"] = get_timestamp(fpath) - mydocs[fname[:-3]] = d - - return mydocs - -def get_docs_for(docs, name): - """build docs for python module""" - import importlib - classname = "" - parts = name.split(".") - - if not parts[-1] in docs: - docs[parts[-1]] = {} - - mydocs = docs[parts[-1]] - try: - obj = importlib.import_module(name) - except ImportError: - # class - name, classname = ".".join(parts[:-1]), parts[-1] - module = importlib.import_module(name) - obj = getattr(module, classname) - - inspect_object_and_update_docs(mydocs, obj) - - # if filename is __init__, list python files and folders with init in folder as _toc - if hasattr(obj, "__file__") and os.path.basename(obj.__file__).split(".")[0]=="__init__": - mydocs["_toc"] = [] - dirname = os.path.dirname(obj.__file__) - for fname in os.listdir(dirname): - fname = cstr(fname) - fpath = os.path.join(dirname, fname) - if os.path.isdir(fpath): - # append if package - if "__init__.py" in os.listdir(fpath): - mydocs["_toc"].append(name + "." + fname) - elif fname.endswith(".py") and not fname.startswith("__init__") and \ - not fname.startswith("test_"): - # append if module - mydocs["_toc"].append(name + "." + fname.split(".")[0]) - - if mydocs.get("_toc"): - for name in mydocs["_toc"]: - get_docs_for(mydocs, name) - - return mydocs - -def inspect_object_and_update_docs(mydocs, obj): - mydocs["_toc"] = getattr(obj, "_toc", "") - if inspect.ismodule(obj): - obj_module = obj - mydocs["_type"] = "module" - else: - obj_module = inspect.getmodule(obj) - mydocs["_type"] = "class" - - mydocs["_icon"] = "code" - mydocs["_gh_source"] = get_gh_url(obj_module.__file__) - mydocs["_modified"] = get_timestamp(obj_module.__file__) - - if not mydocs.get("_intro"): - mydocs["_intro"] = getattr(obj, "__doc__", "") - - for name in dir(obj): - try: - value = getattr(obj, name) - except AttributeError, e: - value = None - - if value: - if (mydocs["_type"]=="module" and inspect.getmodule(value)==obj)\ - or (mydocs["_type"]=="class" and getattr(value, "im_class", None)==obj): - if inspect.ismethod(value) or inspect.isfunction(value): - mydocs[name] = { - "_type": "function", - "_args": inspect.getargspec(value)[0], - "_help": getattr(value, "__doc__", ""), - "_source": inspect.getsource(value) - } - elif inspect.isclass(value): - if not mydocs.get("_toc"): - mydocs["_toc"] = [] - mydocs["_toc"].append(obj.__name__ + "." + value.__name__) - -def get_gh_url(path): - sep = "/lib/" if "/lib/" in path else "/app/" - url = gh_prefix \ - + ("wnframework" if sep=="/lib/" else "erpnext") \ - + ("/blob" if ("." in path) else "/tree") \ - +"/master/" + path.split(sep)[1] - if url.endswith(".pyc"): - url = url[:-1] - return url - -def get_modules(for_module=None): - import importlib - docs = { - "_label": "Modules" - } - if for_module: - modules = [for_module] - else: - modules = webnotes.conn.sql_list("select name from `tabModule Def` order by name") - - docs["_toc"] = ["docs.dev.modules." + d for d in modules] - for m in modules: - prefix = "docs.dev.modules." + m - mydocs = docs[m] = { - "_icon": "th", - "_label": m, - "_toc": [ - prefix + ".doctype", - prefix + ".page", - prefix + ".py_modules" - ], - "doctype": get_doctypes(m), - "page": get_pages(m), - #"report": {}, - "py_modules": { - "_label": "Independent Python Modules for " + m, - "_toc": [] - } - } - - # add stand alone modules - module_path = get_module_path(m) - prefix = prefix + ".py_modules." - for basepath, folders, files in os.walk(module_path): - for f in files: - f = cstr(f) - if f.endswith(".py") and \ - (not f.split(".")[0] in os.path.split(basepath)) and \ - (not f.startswith("__")): - - module_name = ".".join(os.path.relpath(os.path.join(basepath, f), - "../app").split(os.path.sep))[:-3] - - # import module - try: - module = importlib.import_module(module_name) - # create a new namespace for the module - module_docs = mydocs["py_modules"][f.split(".")[0]] = {} - - # add to toc - mydocs["py_modules"]["_toc"].append(prefix + f.split(".")[0]) - - inspect_object_and_update_docs(module_docs, module) - except TypeError, e: - webnotes.errprint("TypeError in importing " + module_name) - except IndentationError, e: - continue - - module_docs["_label"] = module_name - module_docs["_function_namespace"] = module_name - - update_readme(docs[m], m) - docs[m]["_gh_source"] = get_gh_url(module_path) - - return docs - -def get_pages(m): - import importlib - pages = webnotes.conn.sql_list("""select name from tabPage where module=%s""", m) - prefix = "docs.dev.modules." + m + ".page." - docs = { - "_icon": "file-alt", - "_label": "Pages", - "_toc": [prefix + d for d in pages] - } - for p in pages: - page = webnotes.doc("Page", p) - mydocs = docs[p] = { - "_label": page.title or p, - "_type": "page", - } - update_readme(mydocs, m, "page", p) - mydocs["_modified"] = page.modified - - # controller - page_name = scrub(p) - try: - page_controller = importlib.import_module(scrub(m) + ".page." + page_name + "." + page_name) - inspect_object_and_update_docs(mydocs, page_controller) - except ImportError, e: - pass - - return docs - -def get_doctypes(m): - doctypes = webnotes.conn.sql_list("""select name from - tabDocType where module=%s order by name""", m) - prefix = "docs.dev.modules." + m + ".doctype." - docs = { - "_icon": "th", - "_label": "DocTypes", - "_toc": [prefix + d for d in doctypes] - } - - for d in doctypes: - meta = webnotes.get_doctype(d) - meta_p = webnotes.get_doctype(d, True) - doc_path = get_doc_path(m, "DocType", d) - - mydocs = docs[d] = { - "_label": d, - "_icon": meta[0].icon, - "_type": "doctype", - "_gh_source": get_gh_url(doc_path), - "_toc": [ - prefix + d + ".model", - prefix + d + ".permissions", - prefix + d + ".controller_server" - ], - } - - update_readme(mydocs, m, "DocType", d) - - # parents and links - links, parents = [], [] - for df in webnotes.conn.sql("""select * from tabDocField where options=%s""", - d, as_dict=True): - if df.parent: - if df.fieldtype=="Table": - parents.append(df.parent) - if df.fieldtype=="Link": - links.append(df.parent) - - if parents: - mydocs["_intro"] += "\n\n#### Child Table Of:\n\n- " + "\n- ".join(list(set(parents))) + "\n\n" - - if links: - mydocs["_intro"] += "\n\n#### Linked In:\n\n- " + "\n- ".join(list(set(links))) + "\n\n" - - if meta[0].issingle: - mydocs["_intro"] += "\n\n#### Single DocType\n\nThere is no table for this DocType and the values of the Single instance are stored in `tabSingles`" - - # model - modeldocs = mydocs["model"] = { - "_label": d + " Model", - "_icon": meta[0].icon, - "_type": "model", - "_intro": "Properties and fields for " + d, - "_gh_source": get_gh_url(os.path.join(doc_path, scrub(d) + ".txt")), - "_fields": [df.fields for df in meta.get({"doctype": "DocField"})], - "_properties": meta[0].fields, - "_modified": meta[0].modified - } - - # permissions - from webnotes.modules.utils import peval_doclist - with open(os.path.join(doc_path, - scrub(d) + ".txt"), "r") as txtfile: - doclist = peval_doclist(txtfile.read()) - - permission_docs = mydocs["permissions"] = { - "_label": d + " Permissions", - "_type": "permissions", - "_icon": meta[0].icon, - "_gh_source": get_gh_url(os.path.join(doc_path, scrub(d) + ".txt")), - "_intro": "Standard Permissions for " + d + ". These can be changed by the user.", - "_permissions": [p for p in doclist if p.doctype=="DocPerm"], - "_modified": doclist[0]["modified"] - } - - # server controller - server_controller_path = os.path.join(doc_path, scrub(d) + ".py") - controller_docs = mydocs["controller_server"] = { - "_label": d + " Server Controller", - "_type": "_class", - "_gh_source": get_gh_url(server_controller_path) - } - - b = webnotes.bean([{"doctype": d}]) - b.make_controller() - if not getattr(b.controller, "__doc__"): - b.controller.__doc__ = "Controller Class for handling server-side events for " + d - inspect_object_and_update_docs(controller_docs, b.controller) - - # client controller - if meta_p[0].fields.get("__js"): - client_controller_path = os.path.join(doc_path, scrub(d) + ".js") - if(os.path.exists(client_controller_path)): - mydocs["_toc"].append(prefix + d + ".controller_client") - client_controller = mydocs["controller_client"] = { - "_label": d + " Client Controller", - "_icon": meta[0].icon, - "_type": "controller_client", - "_gh_source": get_gh_url(client_controller_path), - "_modified": get_timestamp(client_controller_path), - "_intro": "Client side triggers and functions for " + d, - "_code": meta_p[0].fields["__js"], - "_fields": [d.fieldname for d in meta_p if d.doctype=="DocField"] - } - - return docs - -def update_readme(mydocs, module, doctype=None, name=None): - if doctype: - readme_path = os.path.join(get_doc_path(module, doctype, name), "README.md") - else: - readme_path = os.path.join(get_module_path(module), "README.md") - - mydocs["_intro"] = "" - - if os.path.exists(readme_path): - with open(readme_path, "r") as readmefile: - mydocs["_intro"] = readmefile.read() - mydocs["_modified"] = get_timestamp(readme_path) - -def prepare_docs(force=False): - os.chdir(get_path("public")) - if not os.path.exists("docs"): - os.mkdir("docs") - - if force: - shutil.rmtree("docs/css") - - if not os.path.exists("docs/css"): - os.mkdir("docs/css") - os.mkdir("docs/css/font") - os.system("cp ../lib/public/css/bootstrap.css docs/css") - os.system("cp ../lib/public/css/font-awesome.css docs/css") - os.system("cp ../lib/public/css/font/* docs/css/font") - os.system("cp ../lib/public/css/prism.css docs/css") - - # clean links in font-awesome - with open("docs/css/font-awesome.css", "r") as fontawesome: - t = fontawesome.read() - t = t.replace("../lib/css/", "") - with open("docs/css/font-awesome.css", "w") as fontawesome: - fontawesome.write(t) - - # copy latest docs.css - os.system("cp ../lib/core/doctype/documentation_tool/docs.css docs/css") - - - if force: - shutil.rmtree("docs/js") - - if not os.path.exists("docs/js"): - os.mkdir("docs/js") - os.system("cp ../lib/public/js/lib/bootstrap.min.js docs/js") - os.system("cp ../lib/public/js/lib/jquery/jquery.min.js docs/js") - os.system("cp ../lib/public/js/lib/prism.js docs/js") - - if force: - os.remove("docs/img/splash.svg") - - if not os.path.exists("docs/img/splash.svg"): - if not os.path.exists("docs/img"): - os.mkdir("docs/img") - os.system("cp ../app/public/images/splash.svg docs/img") - -@webnotes.whitelist() -def write_docs(data, build_sitemap=None, domain=None): - from webnotes.utils import global_date_format - if webnotes.session.user != "Administrator": - raise webnotes.PermissionError - - if isinstance(data, basestring): - data = json.loads(data) - - template = webnotes.get_template("app/docs/templates/docs.html") - - data["index"] = data["docs"] - data["docs"] = None - for name, d in data.items(): - if d: - if not d.get("title"): - d["title"] = d["_label"] - if d.get("_parent_page")=="docs.html": - d["_parent_page"] = "index.html" - if not d.get("_icon"): - d["_icon"] = "icon-file-alt" - if not d["_icon"].startswith("icon-"): - d["_icon"] = "icon-" + d["_icon"] - if d.get("_modified"): - d["_modified"] = global_date_format(d["_modified"]) - - with open(get_path("public", "docs", name + ".html"), "w") as docfile: - if not d.get("description"): - d["description"] = "Help pages for " + d["title"] - html = template.render(d) - docfile.write(html.encode("utf-8", errors="ignore")) - - if build_sitemap and domain: - if not domain.endswith("/"): - domain = domain + "/" - content = "" - for fname in os.listdir(get_path("public", "docs")): - fname = cstr(fname) - if fname.endswith(".html"): - content += sitemap_link_xml % (domain + fname, - get_timestamp(get_path("public", "docs", fname))) - - with open(get_path("public", "docs", "sitemap.xml"), "w") as sitemap: - sitemap.write(sitemap_frame_xml % content) - -def write_static(): - webnotes.local.session = webnotes._dict({"user":"Administrator"}) - pages = prepare_static_pages() - write_docs(pages) - prepare_docs() - -def prepare_static_pages(): - from markdown2 import markdown - - pages = get_static_pages() - autogenerated_roots = ["docs.dev.framework.server", "docs.dev.framework.client", - "docs.dev.modules"] - - # build toc - for name, page in pages.items(): - if name in autogenerated_roots: - del pages[name] - continue - - # toc - if page.get("_toc"): - prev = None - page["_toc_links"] = [] - for child in page["_toc"]: - if child in pages: - page["_toc_links"].append({ - "link": child + ".html", - "label": pages[child]["_label"] - }) - - if not "_child_title" in page: - page["_child_title"] = pages[child]["_label"] - page["_child_page"] = child + ".html" - - pages[child]["_parent_title"] = page["_label"] - pages[child]["_parent_page"] = name + ".html" - - if prev: - prev["_next_title"] = pages[child]["_label"] - prev["_next_page"] = child + ".html" - - prev = pages[child] - - # breadcrumbs - if name!="docs": - fullname = "" - page["_breadcrumbs"] = [] - for p in name.split(".")[:-1]: - fullname = fullname + (fullname and "." or "") + p - page["_breadcrumbs"].append({ - "link": (fullname=="docs" and "index" or fullname) + ".html", - "label": pages[fullname]["_label"] - }) - - page["content"] = markdown(page["_intro"]) - - return pages - -def get_timestamp(path): - return datetime.datetime.fromtimestamp(os.path.getmtime(path)).strftime("%Y-%m-%d") - - -sitemap_frame_xml = """ -%s -""" - -sitemap_link_xml = """\n%s%s""" - -if __name__=="__main__": - write_static() - \ No newline at end of file diff --git a/core/doctype/documentation_tool/documentation_tool.txt b/core/doctype/documentation_tool/documentation_tool.txt deleted file mode 100644 index fcbdcab437..0000000000 --- a/core/doctype/documentation_tool/documentation_tool.txt +++ /dev/null @@ -1,131 +0,0 @@ -[ - { - "creation": "2013-06-20 10:40:02", - "docstatus": 0, - "modified": "2013-07-05 14:36:00", - "modified_by": "Administrator", - "owner": "Administrator" - }, - { - "custom": 0, - "description": "Documentation Generator Console", - "doctype": "DocType", - "hide_heading": 0, - "hide_toolbar": 1, - "icon": "icon-book", - "issingle": 1, - "module": "Core", - "name": "__common__" - }, - { - "doctype": "DocField", - "name": "__common__", - "parent": "Documentation Tool", - "parentfield": "fields", - "parenttype": "DocType", - "permlevel": 0 - }, - { - "create": 1, - "doctype": "DocPerm", - "name": "__common__", - "parent": "Documentation Tool", - "parentfield": "permissions", - "parenttype": "DocType", - "permlevel": 0, - "read": 1, - "role": "Administrator", - "write": 1 - }, - { - "doctype": "DocType", - "name": "Documentation Tool" - }, - { - "doctype": "DocField", - "fieldname": "build_pages", - "fieldtype": "Check", - "label": "Build Pages" - }, - { - "doctype": "DocField", - "fieldname": "build_modules", - "fieldtype": "Check", - "label": "Build Modules" - }, - { - "doctype": "DocField", - "fieldname": "build_server_api", - "fieldtype": "Check", - "label": "Build Server API" - }, - { - "allow_on_submit": 0, - "description": "Write sitemap.xml", - "doctype": "DocField", - "fieldname": "build_sitemap", - "fieldtype": "Check", - "hidden": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Build Sitemap", - "no_copy": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0 - }, - { - "doctype": "DocField", - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "depends_on": "build_pages", - "doctype": "DocField", - "fieldname": "page_name", - "fieldtype": "Data", - "label": "Page Name" - }, - { - "depends_on": "build_modules", - "doctype": "DocField", - "fieldname": "module_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Module Name", - "read_only": 0, - "reqd": 0 - }, - { - "depends_on": "build_server_api", - "doctype": "DocField", - "fieldname": "python_module_name", - "fieldtype": "Data", - "label": "Python Module Name" - }, - { - "depends_on": "build_sitemap", - "description": "example: http://help.erpnext.com", - "doctype": "DocField", - "fieldname": "sitemap_domain", - "fieldtype": "Data", - "label": "Sitemap Domain" - }, - { - "doctype": "DocField", - "fieldname": "log", - "fieldtype": "Section Break", - "label": "Log" - }, - { - "doctype": "DocField", - "fieldname": "out", - "fieldtype": "HTML", - "label": "Out" - }, - { - "doctype": "DocPerm" - } -] \ No newline at end of file diff --git a/docs/docs.attributions.md b/docs/docs.attributions.md deleted file mode 100644 index b226402608..0000000000 --- a/docs/docs.attributions.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -{ - "_label": "Attributions" -} ---- -ERPNext is made using these amazing Open Source Projects. - -### System Requirements: - -1. [Linux Operating System](http://en.wikipedia.org/wiki/Linux): The operating system that brought a revolution in Open Source software. -1. [MySQL Database](http://www.mysql.com/): The world's most popular Open Source Database. -1. [Apache HTTPD web server](http://httpd.apache.org): The Number One HTTP Server On The Internet. -1. [Memcached](http://memcached.org/): Free & open source, high-performance, distributed memory object caching system. - -### Tools and Languages: - -1. [Python Programming Language](http://python.org/): The "batteries included" language that lets you write elegant code, quickly. With third-party modules: - - MySQLdb - - pytz - - jinja2 - - markdown2 - - dateutil - - termcolor - - python-memcached - - requests - - chardet - - pygeoip - - dropbox - - google-api-python-client -1. [Git - Source Code Management](http://git-scm.com/): Git - Source Code Management - -### Libraries and Frameworks - -1. [wnframework](https://github.com/webnotes/wnframework): The full stack Python + Javascript web application framework on which ERPNext is built. -1. [JQuery](http://jquery.com/): The write less, do more Javascript Library. -1. [JQuery UI](http://jqueryui.com/): A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library. -1. [Bootstrap](http://twitter.github.com/bootstrap/index.html): Sleek, intuitive, and powerful front-end framework for faster and easier web development. -1. [Font Awesome](http://fortawesome.github.com/Font-Awesome/): The iconic font designed for use with Twitter Bootstrap. -1. [SlickGrid](https://github.com/mleibman/SlickGrid): A lightning fast JavaScript grid/spreadsheet. -1. [FullCalendar](http://arshaw.com/fullcalendar/): FullCalendar is a jQuery plugin that provides a full-sized, drag and drop calendar. -1. [Flot Charting Library](http://www.flotcharts.org/): Attractive JavaScript plotting for jQuery. -1. [Ace Code Editor](http://ace.ajax.org/): High Performance Code Editor for the web. -1. [JQuery.Gantt](http://taitems.github.com/jQuery.Gantt/): Draw Gantt charts with the famous jQuery ease of development. -1. [JQuery Tag-it](http://aehlke.github.io/tag-it/): Simple and configurable tag editing widget with autocomplete support. -1. [JSColor](http://jscolor.com/): HTML/Javascript Color Picker. -1. [QUnit](http://qunitjs.com/): A JavaScript Unit Testing framework. -1. [Downloadify](https://github.com/dcneiner/Downloadify): A tiny javascript + Flash library that enables the creation and download of text files without server interaction. -1. [GeoLite](http://dev.maxmind.com/geoip/geolite): GeoLite data created by MaxMind, available from https://www.maxmind.com. - ---- - -For more information please write to us at support@erpnext.com \ No newline at end of file diff --git a/docs/docs.dev.framework.client.md b/docs/docs.dev.framework.client.md deleted file mode 100644 index 7f26731cb3..0000000000 --- a/docs/docs.dev.framework.client.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -{ - "_label": "Client Side - JavaScript", - "_toc": [ - "wn" - ] -} ---- -All `wnframework` methods are linked to the `wn` namespace. Browse through the modules -to understand the various functions available. \ No newline at end of file diff --git a/docs/docs.dev.framework.md b/docs/docs.dev.framework.md deleted file mode 100644 index b29554cb77..0000000000 --- a/docs/docs.dev.framework.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -{ - "_label": "Framework", - "_toc": [ - "docs.dev.framework.server", - "docs.dev.framework.client" - ] -} ---- -wnframework has two major libraries one on the client and other on the server. - -### Server - -The server-side functions are called by the web server (Apache HTTPD) when a user make a web request. The framework handles user authentication, sessions, permissions, business logic and much more. - -Serverside functions are also called when static website pages are generated and via a scheduler for triggering scheduled events. - -### Client - -Once the user is logged in, a javascript based application is loaded. This application communicates with the server to display data, forms, trigger events, run reports etc. - -The application is built on standard 3rd party javascript tools like jQuery, Bootstrap, -SlickGrid and others. \ No newline at end of file diff --git a/docs/docs.dev.framework.server.md b/docs/docs.dev.framework.server.md deleted file mode 100644 index 625db95ce3..0000000000 --- a/docs/docs.dev.framework.server.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -{ - "_label": "Server Side - Python", - "_toc": [ - "webnotes" - ] -} ---- -The `webnotes` Python module contains all the functions used to manage the application code. \ No newline at end of file diff --git a/docs/docs.dev.quickstart.md b/docs/docs.dev.quickstart.md deleted file mode 100644 index 12b000edab..0000000000 --- a/docs/docs.dev.quickstart.md +++ /dev/null @@ -1,202 +0,0 @@ ---- -{ - "_label": "Quickstart" -} ---- -### Preamble - -wnframework is, a Python based, meta-data driven framework. The framework implements -its own object-relational model (ORM) and provides a rich client interface based on -Javascript. It is primararily used to develop [ERPNext](https://github.com/webnotes/erpnext) - -To develop on wnframework, you must have a basic understanding of how web applications -and client-server architectures work. On the server-side, requests are handled by Python -modules via CGI. So each request is a new thread and there is no state preservation on -the server. Session data is stored in memcached server. - -WNFramework also has way you metadata is defined, called a `DocType`. Everything -object in the system like a Customer or Journal Voucher is a `DocType`. - -Overall, be prepared for a slight learning curve. A lot of the inner code / design -is not very elegant and you might encounter spaghetti at certain places. We are working -to reduce all of that. - ---- - -## Meta data - -Base model in wnframework is called a `DocType`. A `DocType` represents a database table, -a web form and a controller to execute business logic. In classical MVC terms it is all -three model, view and controller to an extent. - -`DocType` objects have `DocField`s that are properties of the model. - ---- - -## Client-Server Setup - -Let us understand how to setup web folders via ERPNext - -An ERPNext setup contains 2 repositories [erpnext](/webnotes/erpnext) and -[wnframework](/webnotes/wnframework). In the main folder of the erpnext setup there -are 3 folders: - - + lib - + app - + public - -The **lib** folder represents *wnframework*, the **app** folder represents *erpnext* and -the **public** folder is served on the web. - -To build the public folder for the first time, run this utility from the base folder: - -`$ lib/wnf.py -b` - -All web pages are served by `public/web.py` and all data requests are served -by `public/server.py` - -The server-side libraries are in `lib/webnotes` and client-side libraries are -in `lib/public/wn` folders. - -### Requests & Routings - -There are 2 types of requests, requests for web pages (when the user is not logged in) and -data requests when the user is logged in. Let us see data requests: - -All data requests are made on `public/server.py`. The method and parameters are passed as -form parameters. - -The `cmd` paramter represents the python method to be executed. This is the "routing" used -in wnframwork. Use the `@webnotes.whitelist()` decorator to whitelist a particular method -to be accessible by the web. - -For example, the request: - -`server.py?cmd=accounts.utils.get_account&account_name=Test` - -will call the `get_account` method in `app/accounts/utils.py`. - -#### Repsonse - -The return to that will be sent as a JSON object - - { - "message": "returned by get_account", - "server_messages":"Any popup messages to be displayed", - "exc": "Any exceptions encountered" - } - -Once the control is passed on to the method, the response is sent back via JSON. - ---- - -## Front End - -The front end is a Javascript based client application. You can login by opening the login -page from your browser. If you have setup your apache routes correctly, just go to -`localhost/public/login` or equivalent to see the login page. This actually translates -into `public/web.py?page=login`. - -Once you login, you will be redirected to `app.html` that fires up the application front-end. - -### URL routing: - -Different pages / objects are accessed by url fragments `#` - -#### Forms - -All objects are accessible via `#Form/[DocType]/[Doument Name]` on the URL. - -To open the customer **DocType**, you can go to `#Form/DocType/Customer` or to open -a Customer, **Customer A**, go to `#Form/Customer/Customer A` - -#### Pages - -Static pages in the application are accessed by their name. For example, the home -page called `desktop` can be accessed by `#desktop` - -#### Client Application - -The client application is bunch of js libraries that help in navigation, rendering -forms, reports and other components. The application code in `public/js/all-app.js` -is built by combining files specified in `lib/public/build.json` and `app/public/build.json`. - To rebuild the client application after making a change, call `lib/wnf.py -b` from the -command line. - ---- - -## Application / Module Development - -### Creating / Editing DocTypes - -To create or edit the **DocType** "schema" you will have to fire the front-end via a -web-browser and login as Administrator. To open a **DocType**, -go to Document > Search > DocType and select the **DocType** to edit. - -The **DocType** form should be self explanatory. It has a list of fields that are -used for both the database table and form. Special fields like `Column Break` and -`Section Break` are present to make the form layout that is processed sequentially. - -DocType is discovered via permissions (`DocPerm`) and by URL routes. - -Once you save a **DocType**, the database schema is automatically update, while -developing, you should fire up a mysql command-line or viewer to see the impact -of your database changes. - -### Adding code to DocTypes - -You can add business logic by writing event code on both client and server side. -The server side events are written in Python and client side events are written in -Javascript. - -The files from where these events are picked up are in the module folders in the -repositories. Apart from the `core` module, all modules are parts -of **erpnext** (`app` folder). Each DocType has its own folder in the module in a -folder called `doctype`. If you browse the files of **erpnext**, you should be able -to locate these files easily. - -#### Server-side modules - -For example, the server-side script for DocType **Account** in module **Accounts** -will be present in the folder `app/accounts/doctype/account/account.py` - -The events are declared as a part of class called `DocType`. In the `DocType` -class there are two main useful properties: - -- `doc`: Represents the main record. -- `doclist`: Represents list of records (including child records) that are associated -with this DocType. For example the `doclist` of **Sales Order** will have the main record -and all **Sales Order Item** records. - -The main serverside events are: - -- `validate`: Called before the `INSERT` or `UPDATE` method is called. -- `on_update`: Called after saving. -- `on_submit`: Called after submission -- `on_cancel`: Called after cancellation. - -See a sample server side file for more info! - ---- - -## Custom UI: Pages - -Custom UI like **Chart of Accounts** etc, is made by Pages. Pages are free form virtual -pages in that are rendered on the client side. A page can have an `.html` (layout), -`.py` (server calls), `.js` (user interface) and `.css` (style) components. - -Understand how pages work, it is best to open an existing page and see how it works. - ---- - -## Patching & Deployment - -Data / schema changes are done to wnframwork via patches released in the `app/patches` -module (see erpnext folder for more details). To run all latest patches that have not -been executed, run `lib/wnf.py -l` - -wnframework deployment is done by the `lib/wnf.py` utility. - -See `lib/wnf.py --help` for more help. - -_Good luck!_ diff --git a/wnf.py b/wnf.py index ecc6e68281..de9248a246 100755 --- a/wnf.py +++ b/wnf.py @@ -125,8 +125,6 @@ def setup_utilities(parser): help="Move site to different directory") parser.add_argument("--with_files", default=False, action="store_true", help="Also take backup of files") - parser.add_argument("--docs", default=False, action="store_true", - help="Build docs") parser.add_argument("--domain", nargs="*", help="Get or set domain in Website Settings") parser.add_argument("--make_conf", nargs="*", metavar=("DB-NAME", "DB-PASSWORD"), @@ -386,11 +384,6 @@ def move(site=None, dest_dir=None): webnotes.destroy() return os.path.basename(final_new_path) -@cmd -def docs(): - from core.doctype.documentation_tool.documentation_tool import write_static - write_static() - @cmd def domain(host_url=None, site=None): webnotes.connect(site=site)