[docs] removed from repository

This commit is contained in:
Anand Doshi 2013-11-27 19:01:31 +05:30
parent 959f43c411
commit 6f3a3e18ca
12 changed files with 0 additions and 1674 deletions

View file

@ -1,3 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

View file

@ -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;
}

View file

@ -1,101 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<meta name="description" content="{{ description }}">
<meta name="generator" content="wnframework">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/prism.js"></script>
<link type="text/css" rel="stylesheet" href="css/bootstrap.css">
<link type="text/css" rel="stylesheet" href="css/font-awesome.css">
<link type="text/css" rel="stylesheet" href="css/prism.css">
<link type="text/css" rel="stylesheet" href="css/docs.css">
</head>
<body>
<header>
{% block navbar %}{% endblock %}
</header>
<div class="container" style=" margin-top: 30px;">
<div class="content row">
<div class="col-md-12">
{%- if not _no_title %}
<h1 class="pull-right text-muted" style="margin-top:0px;"><i class="{{ _icon }}"></i></h1>
<h1>{{ _label }}</h1>
<ul class="breadcrumb">
{%- for b in _breadcrumbs -%}
<li><a href="{{ b.link }}">{{ b.label }}</a></li>
{%- endfor -%}
<li class="active">{{ _label }}</li>
</ul>
{%- if _toc_links and not _no_toc %}
<!-- toc -->
<div class="well">
<h4>Contents</h4>
<ol>
{%- for t in _toc_links %}
<li><a href="{{ t.link }}">{{ t.label }}</a></li>
{% endfor -%}
</ol>
</div>
<!-- end toc -->
{%- endif -%}
{% endif -%}
{{ content }}
<br>
<!-- footer -->
<p style="font-size: 80%;" class="text-muted pull-right">
{% if _gh_source -%}
<a href="{{ _gh_source }}" target="_blank"><i class="icon-github"></i> Source</i></a>
{%- endif -%}
{% if _modified -%}
{%- if _gh_source %} | {% endif -%}
<span>Last Updated: {{ _modified }}</span>
{%- endif %}
</p>
<div class="clearfix"></div>
<!-- footer navigation -->
{%- if _parent_title -%}
<div class="btn-group pull-right" style="margin: 15px 0px;">
<a class='btn btn-default' href="{{ _parent_page }}">
<i class="icon-arrow-up"></i> {{ _parent_title }}</a>
{% if _next_title -%}
<a class='btn btn-default' href="{{ _next_page }}">
<i class="icon-arrow-right"></i> {{ _next_title }}</a>
{%- endif -%}
{% if _child_title -%}
<a class='btn btn-default' href="{{ _child_page }}">
<i class="icon-arrow-down"></i> {{ _child_title }}</a>
{%- endif -%}
</div>
{%- endif -%}
<!-- end footer -->
</div>
</div>
<div class="clearfix"></div>
{% block footer %}{% endblock %}
<p>&nbsp;</p>
</div>
<script type="text/javascript">
$(document).ready(function() {
$("[data-toggle]").on("click", function() {
$("[data-target='"+ $(this).attr("data-toggle") +"']").toggle();
return false;
});
});
$(".dropdown-toggle").dropdown();
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-8911157-6']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

View file

@ -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 = $("<div class='docs'>"),
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...<br>");
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...<br>");
make_page("docs");
logarea.append("Writing...<br>");
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) {
$('<h4 class="text-muted">No docs</h4>').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) {
$("<p>").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('<tr>\
<td>%(label)s</td>\
<td>%(value)s</td>\
<td>%(description)s</td>\
</tr>', 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('<tr>\
<td>%(idx)s</td>\
<td>%(fieldname)s</td>\
<td>%(label)s</td>\
<td>%(fieldtype)s</td>\
<td>%(options)s</td>\
</tr>', 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('<tr>\
<td>%(idx)s</td>\
<td>%(role)s</td>\
<td>%(permlevel)s</td>\
<td>%(read)s</td>\
<td>%(write)s</td>\
<td>%(create)s</td>\
<td>%(submit)s</td>\
<td>%(cancel)s</td>\
<td>%(amend)s</td>\
<td>%(report)s</td>\
<td>%(match)s</td>\
</tr>', 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 = $("<table class='table table-bordered' style='table-layout: fixed;'>\
<thead></thead>\
<tbody></tbody>\
</table>").appendTo(this.parent);
if(columns) {
$.each(columns || [], function(i, c) {
$("<th>")
.css({"width": c.width})
.html(c.label)
.appendTo(table.find("thead"))
});
}
return table.find("tbody");
},
h3: function(txt) {
$("<h3>").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('<p style="font-size: 90%;">\
<a href="#" data-toggle="%(name)s">View Source</a></p>\
<pre data-target="%(name)s" style="display: none; font-size: 12px; \
background-color: white; border-radius: 0px;\
overflow-x: auto; word-wrap: normal;"><code class="language-%(lang)s">\
%(code)s</code></pre>', {
name: name,
code: value._source || code,
lang: (value._source ? "python" : "javascript")
});
}
try {
$(repl('<tr>\
<td style="width: 30%;">%(name)s</td>\
<td>\
<h5>Usage:</h5>\
<pre>%(namespace)s%(name)s(%(args)s)</pre>\
%(help)s\
%(source)s\
</td>\
</tr>', {
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;
}
})

View file

@ -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 = """<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">%s
</urlset>"""
sitemap_link_xml = """\n<url><loc>%s</loc><lastmod>%s</lastmod></url>"""
if __name__=="__main__":
write_static()

View file

@ -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"
}
]

View file

@ -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 <a href="https://www.maxmind.com">https://www.maxmind.com</a>.
---
For more information please write to us at support@erpnext.com

View file

@ -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.

View file

@ -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.

View file

@ -1,9 +0,0 @@
---
{
"_label": "Server Side - Python",
"_toc": [
"webnotes"
]
}
---
The `webnotes` Python module contains all the functions used to manage the application code.

View file

@ -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!_

7
wnf.py
View file

@ -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)