Merge branch 'responsive' of github.com:webnotes/wnframework into responsive

This commit is contained in:
Anand Doshi 2013-07-15 18:28:37 +05:30
commit c8a6481d1f
12 changed files with 268 additions and 219 deletions

View file

@ -6,19 +6,22 @@ body {
line-height: 25px;
}
img {
max-width: 100%;
}
.container {
max-width: 767px;
}
.navbar-inverse {
background-color: #2980b9;
.navbar {
background-color: #ffffff;
border-bottom: 1px solid #dddddd;
}
.navbar-inverse .navbar-text,
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a
.navbar .navbar-nav > li > a:hover
{
color: #eeeeee;
color: #444444;
}
h1 {
@ -61,3 +64,34 @@ blockquote p {
.erpnext-logo rect {
fill: #ffffff !important;
}
.btn-default {
color: #ffffff;
background-color: #a7a9aa;
border-color: #a7a9aa;
}
.btn-default:hover,
.btn-default:focus,
.btn-default:active,
.btn-default.active {
background-color: #9a9c9d;
border-color: #8d9091;
}
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
background-color: #a7a9aa;
border-color: #a7a9aa;
}

View file

@ -0,0 +1,92 @@
<!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>
<div class="navbar navbar-fixed-top">
<div class="container">
<button type="button" class="navbar-toggle"
data-toggle="collapse" data-target=".navbar-responsive-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">
<object data="img/splash.svg" class="erpnext-logo"
type="image/svg+xml"></object> erpnext</a>
<div class="nav-collapse collapse navbar-responsive-collapse">
<ul class="nav navbar-nav">
<li><a href="docs.user.html">User</a></li>
<li><a href="docs.dev.html">Developer</a></li>
<li><a href="docs.download.html">Download</a></li>
<li><a href="docs.community.html">Community</a></li>
<li><a href="docs.blog.html">Blog</a></li>
</ul>
</div>
</div>
</div>
</header>
<div class="container" style=" margin-top: 70px;">
<!-- div class="logo" style="margin-bottom: 15px; height: 71px;">
<a href="docs.html">
<img src="img/erpnext-2013.png" style="width: 71px; margin-top: -10px;" />
</a>
<span style="font-size: 37px; color: #888; display: inline-block;
margin-left: 8px;">erpnext</span>
</div -->
<div class="content row">
<div class="col col-lg-12">
{{ content }}
</div>
</div>
<div class="clearfix"></div>
<hr />
<div class="footer text-muted" style="font-size: 80%;">
<div class="content row">
<div class="col col-lg-12">
&copy; <a href="https://erpnext.com">Web Notes Technologies Pvt Ltd.</a><br>
ERPNext is an <a href="https://github.com/webnotes/erpnext" target="_blank">
open source project</a>. Code licensed under the
<a href="https://www.gnu.org/licenses/gpl.html">GNU/GPL License</a>.
Documentation Licensed under <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA-3.0</a>.<br>
<a href="docs.user.help.html">Get Help</a> / <a href="https://erpnext.com/contact">Get in touch</a> /
<a href="https://erpnext.com">Buy Hosting or Support Services</a>
</div>
</div>
</div>
<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-9']);
_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,32 +1,3 @@
/*
Todo:
- make global toc
- static pages in markdown (in sources folder)
- web interface
- building an application
- customizing an application
- generating web pages
- help / comments in markdown
- pages
- doctype
- links
- properties
- methods
- events (server, client)
Documentation API
Every module (namespace) / class will have a page
- _toc
- _path
- _label
- _intro
- _type (class, function, module, doctype etc)
- [list of functions / objects / classes]
*/
wn.require("lib/public/js/lib/beautify-html.js");
cur_frm.cscript.onload = function(doc) {
@ -50,6 +21,7 @@ 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();
@ -125,6 +97,7 @@ wn.docs.generate_all = function(logarea) {
},
callback: function(r) {
logarea.append("Wrote " + keys(wn.docs.to_write).length + " pages.");
cur_frm = original_cur_frm;
}
});
}
@ -316,6 +289,9 @@ wn.docs.DocsPage = Class.extend({
else
page_icon = "file-text-alt";
}
if(page_icon.substr(0,5)==="icon-") page_icon = page_icon.substr(5);
var icon = $('<h1 class="pull-right text-muted"><i class="icon-'+
page_icon +'"></i></h1>')
.appendTo(this.parent);
@ -615,7 +591,7 @@ wn.docs.DocsPage = Class.extend({
}
wn.docs.to_write[this.namespace] = {
title: wn.app.name + ": " + this.obj._label || wn.docs.get_short_name(this.namespace),
title: wn.app.name + ": " + (this.obj._label || wn.docs.get_short_name(this.namespace)),
content: html_beautify(this.parent.html())
}
}

View file

@ -104,7 +104,7 @@ def inspect_object_and_update_docs(mydocs, obj):
if not mydocs.get("_intro"):
mydocs["_intro"] = getattr(obj, "__doc__", "")
for name in dir(obj):
try:
value = getattr(obj, name)
@ -112,13 +112,19 @@ def inspect_object_and_update_docs(mydocs, obj):
value = None
if value:
if inspect.ismethod(value) or (inspect.isfunction(value) and inspect.getmodule(value)==obj):
mydocs[name] = {
"_type": "function",
"_args": inspect.getargspec(value)[0],
"_help": getattr(value, "__doc__", ""),
"_source": inspect.getsource(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/"
@ -149,14 +155,13 @@ def get_modules(for_module=None):
"_toc": [
prefix + ".doctype",
prefix + ".page",
prefix + ".report",
prefix + ".py_modules"
],
"doctype": get_doctypes(m),
"page": get_pages(m),
#"report": {},
"py_modules": {
"_label": "Independant Python Modules for " + m,
"_label": "Independent Python Modules for " + m,
"_toc": []
}
}
@ -239,7 +244,7 @@ def get_doctypes(m):
mydocs = docs[d] = {
"_label": d,
"_icon": "sitemap",
"_icon": meta[0].icon,
"_type": "doctype",
"_gh_source": get_gh_url(doc_path),
"_toc": [
@ -273,7 +278,7 @@ def get_doctypes(m):
# model
modeldocs = mydocs["model"] = {
"_label": d + " Model",
"_icon": "sitemap",
"_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")),
@ -291,7 +296,7 @@ def get_doctypes(m):
permission_docs = mydocs["permissions"] = {
"_label": d + " Permissions",
"_type": "permissions",
"_icon": "shield",
"_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"],
@ -314,12 +319,12 @@ def get_doctypes(m):
# client controller
if meta_p[0].fields.get("__js"):
mydocs["_toc"].append(prefix + d + ".controller_client")
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": "code",
"_icon": meta[0].icon,
"_type": "controller_client",
"_gh_source": get_gh_url(client_controller_path),
"_modified": get_timestamp(client_controller_path),
@ -379,7 +384,10 @@ def prepare_docs():
def write_docs(data, build_sitemap=None, domain=None):
if webnotes.session.user != "Administrator":
raise webnotes.PermissionError
with open(os.path.join(os.path.dirname(__file__), "docs.html"), "r") as docshtml:
docs_template = docshtml.read()
data = json.loads(data)
template = Template(docs_template)
data["index"] = data["docs"]
@ -416,99 +424,3 @@ sitemap_frame_xml = """<?xml version="1.0" encoding="UTF-8"?>
</urlset>"""
sitemap_link_xml = """\n<url><loc>%s</loc><lastmod>%s</lastmod></url>"""
docs_template = """
<!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>
<div class="navbar navbar-fixed-top navbar-inverse">
<div class="container">
<button type="button" class="navbar-toggle"
data-toggle="collapse" data-target=".navbar-responsive-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">
<object data="img/splash.svg" class="erpnext-logo"
type="image/svg+xml"></object> erpnext</a>
<div class="nav-collapse collapse navbar-responsive-collapse">
<ul class="nav navbar-nav">
<li><a href="docs.user.html">User</a></li>
<li><a href="docs.dev.html">Developer</a></li>
<li><a href="docs.download.html">Download</a></li>
<li><a href="docs.community.html">Community</a></li>
<li><a href="docs.blog.html">Blog</a></li>
</ul>
</div>
</div>
</div>
</header>
<div class="container" style=" margin-top: 70px;">
<!-- div class="logo" style="margin-bottom: 15px; height: 71px;">
<a href="docs.html">
<img src="img/erpnext-2013.png" style="width: 71px; margin-top: -10px;" />
</a>
<span style="font-size: 37px; color: #888; display: inline-block;
margin-left: 8px;">erpnext</span>
</div -->
<div class="content row">
<div class="col col-lg-12">
{{ content }}
</div>
</div>
<div class="clearfix"></div>
<hr />
<div class="footer text-muted" style="font-size: 80%;">
<div class="content row">
<div class="col col-lg-12">
&copy; <a href="https://erpnext.com">Web Notes Technologies Pvt Ltd.</a><br>
ERPNext is an <a href="https://github.com/webnotes/erpnext" target="_blank">
open source project</a>. Code licensed under the
<a href="https://www.gnu.org/licenses/gpl.html">GNU/GPL License</a>.
Documentation Licensed under <a href="http://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a>.<br>
<a href="docs.user.help.html">Get Help</a> / <a href="https://erpnext.com/contact">Get in touch</a> /
<a href="https://erpnext.com">Buy Hosting or Support Services</a>
</div>
</div>
</div>
<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-9']);
_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

@ -111,34 +111,4 @@ wn.assets = {
wn.dom.set_style(txt);
}
}
}
wn.markdown = function(txt) {
if(!wn.md2html) {
wn.require('lib/js/lib/showdown.js');
wn.md2html = new Showdown.converter();
}
while(txt.substr(0,1)==="\n") {
txt = txt.substr(1);
}
// remove leading tab (if they exist in the first line)
var whitespace_len = 0,
first_line = txt.split("\n")[0];
while([" ", "\n", "\t"].indexOf(first_line.substr(0,1))!== -1) {
whitespace_len++;
first_line = first_line.substr(1);
}
if(whitespace_len && whitespace_len != first_line.length) {
var txt1 = [];
$.each(txt.split("\n"), function(i, t) {
txt1.push(t.substr(whitespace_len));
})
txt = txt1.join("\n");
}
return wn.md2html.makeHtml(txt);
}
}

View file

@ -41,6 +41,37 @@ wn.tools.downloadify = function(data, roles, me) {
}
};
wn.markdown = function(txt) {
if(!wn.md2html) {
wn.require('lib/js/lib/showdown.js');
wn.md2html = new Showdown.converter();
}
while(txt.substr(0,1)==="\n") {
txt = txt.substr(1);
}
// remove leading tab (if they exist in the first line)
var whitespace_len = 0,
first_line = txt.split("\n")[0];
while([" ", "\n", "\t"].indexOf(first_line.substr(0,1))!== -1) {
whitespace_len++;
first_line = first_line.substr(1);
}
if(whitespace_len && whitespace_len != first_line.length) {
var txt1 = [];
$.each(txt.split("\n"), function(i, t) {
txt1.push(t.substr(whitespace_len));
})
txt = txt1.join("\n");
}
return wn.md2html.makeHtml(txt);
}
wn.tools.to_csv = function(data) {
var res = [];
$.each(data, function(i, row) {

View file

@ -26,6 +26,18 @@ var cur_dialog;
wn.ui.open_dialogs = [];
wn.ui.Dialog = wn.ui.FieldGroup.extend({
_intro:' usage:\n\
\n\
var dialog = new wn.ui.Dialog({\n\
title: "Dialog Title",\n\
fields: [\n\
{fieldname:"field1", fieldtype:"Data", reqd:1, label: "Test 1"},\n\
{fieldname:"field2", fieldtype:"Link", reqd:1, label: "Test 1", options:"Some DocType"},\n\
{fieldname:"mybutton", fieldtype:"Button", reqd:1, label: "Submit"},\n\
]\n\
})\n\
dialog.get_input("mybutton").click(function() { /* do something; */ dialog.hide(); });\n\
dialog.show()',
init: function(opts) {
this.display = false;
if(!opts.width) opts.width = 480;

View file

@ -56,14 +56,15 @@ wn.upload = {
"method": "uploadfile",
args: args,
callback: function(r) {
msgbox.hide();
if(!r._server_messages)
msgbox.hide();
if(r.exc) {
onerror(r);
return;
}
callback(r.message, args.filename || args.file_url, r);
callback(r.message.fileid, r.message.filename, r);
$(document).trigger("upload_complete",
[args.filename, args.file_url]);
[r.message.fileid, r.message.filename]);
}
});
}

View file

@ -29,8 +29,6 @@ import webnotes
import conf
import datetime
_toc = ["webnotes.db.Database"]
class Database:
"""
Open a database connection with the given parmeters, if use_default is True, use the

View file

@ -26,8 +26,8 @@ from webnotes import _
from webnotes.utils import cstr
from webnotes.model import default_fields
def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[], postprocess=None,
ignore_permissions=False):
def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[],
postprocess=None, ignore_permissions=False):
if isinstance(target_doclist, basestring):
target_doclist = json.loads(target_doclist)
@ -38,7 +38,7 @@ def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[]
source_meta = webnotes.get_doctype(from_doctype)
target_meta = webnotes.get_doctype(table_maps[from_doctype]["doctype"])
# main
if target_doclist:
if isinstance(target_doclist[0], dict):
@ -49,8 +49,11 @@ def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[]
target_doc = webnotes.new_doc(table_maps[from_doctype]["doctype"])
map_doc(source.doc, target_doc, table_maps[source.doc.doctype], source_meta, target_meta)
doclist = [target_doc]
if target_doclist:
target_doclist[0] = target_doc
else:
target_doclist = [target_doc]
# children
for source_d in source.doclist[1:]:
table_map = table_maps.get(source_d.doctype)
@ -65,17 +68,20 @@ def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[]
"fieldtype": "Table",
"options": target_doctype
})[0].fieldname
if table_map.get("add_if_empty") and row_exists_in_target(parentfield, target_doclist):
continue
target_d = webnotes.new_doc(target_doctype, target_doc, parentfield)
map_doc(source_d, target_d, table_map, source_meta, target_meta, source.doclist[0])
doclist.append(target_d)
target_doclist.append(target_d)
doclist = webnotes.doclist(doclist)
target_doclist = webnotes.doclist(target_doclist)
if postprocess:
postprocess(source, doclist)
postprocess(source, target_doclist)
return doclist
return target_doclist
def map_doc(source_doc, target_doc, table_map, source_meta, target_meta, source_parent=None):
no_copy_fields = set(\
@ -122,3 +128,13 @@ def map_doc(source_doc, target_doc, table_map, source_meta, target_meta, source_
if "postprocess" in table_map:
table_map["postprocess"](source_doc, target_doc, source_parent)
row_exists_for_parentfield = {}
def row_exists_in_target(parentfield, target_doclist):
global row_exists_for_parentfield
if parentfield not in row_exists_for_parentfield:
row_exists_for_parentfield[parentfield] = True if \
webnotes.doclist(target_doclist).get({"parentfield": parentfield}) else False
return row_exists_for_parentfield[parentfield]

View file

@ -23,7 +23,7 @@
from __future__ import unicode_literals
import webnotes
import os, conf
from webnotes.utils import cstr, get_path
from webnotes.utils import cstr, get_path, cint
from webnotes import _
class MaxFileSizeReachedError(webnotes.ValidationError): pass
@ -41,18 +41,16 @@ def upload():
# save
if filename:
fid, fname = save_uploaded(dt, dn)
filedata = save_uploaded(dt, dn)
elif file_url:
fid, fname = save_url(file_url, dt, dn)
filedata = save_url(file_url, dt, dn)
return {"fid": filedata.name, "filename": filedata.file_name or filedata.file_url }
if fid:
return fid
def save_uploaded(dt, dn):
def save_uploaded(dt, dn):
fname, content = get_uploaded_content()
if content:
fid = save_file(fname, content, dt, dn)
return fid, fname
return save_file(fname, content, dt, dn)
else:
raise Exception
@ -69,7 +67,7 @@ def save_url(file_url, dt, dn):
})
f.ignore_permissions = True
f.insert();
return f.doc.name, file_url
return f.doc
def get_uploaded_content():
# should not be unicode when reading a file, hence using webnotes.form
@ -90,14 +88,25 @@ def save_file(fname, content, dt, dn):
temp_fname = write_file(content)
fname = scrub_file_name(fname)
fpath = os.path.join(files_path, fname)
fname_parts = fname.split(".", -1)
main = ".".join(fname_parts[:-1])
extn = fname_parts[-1]
versions = get_file_versions(files_path, main, extn)
if os.path.exists(fpath):
if cmp(fpath, temp_fname):
# remove new file, already exists!
os.remove(temp_fname)
else:
if versions:
found_match = False
for version in versions:
if cmp(os.path.join(files_path, version), temp_fname):
# remove new file, already exists!
os.remove(temp_fname)
fname = version
found_match = True
break
if not found_match:
# get_new_version name
fname = get_new_fname_based_on_version(files_path, fname)
fname = get_new_fname_based_on_version(files_path, main, extn, versions)
# rename
os.rename(temp_fname, os.path.join(files_path, fname))
@ -115,24 +124,24 @@ def save_file(fname, content, dt, dn):
f.ignore_permissions = True
f.insert();
return f.doc.name
return f.doc
def get_new_fname_based_on_version(files_path, fname):
# new version of the file is being uploaded, add a revision number?
versions = filter(lambda f: f.startswith(fname), os.listdir(files_path))
def get_file_versions(files_path, main, extn):
return filter(lambda f: f.startswith(main) and f.endswith(extn), os.listdir(files_path))
def get_new_fname_based_on_version(files_path, main, extn, versions):
versions.sort()
if "-" in versions[-1]:
version = int(versions[-1].split("-")[-1]) or 1
version = cint(versions[-1].split("-")[-1]) or 1
else:
version = 1
new_fname = fname + "-" + str(version)
new_fname = main + "-" + str(version) + "." + extn
while os.path.exists(os.path.join(files_path, new_fname)):
version += 1
new_fname = fname + "-" + str(version)
new_fname = main + "-" + str(version) + "." + extn
if version > 100:
break # let there be an exception
webnotes.msgprint("Too many versions", raise_exception=True)
return new_fname

View file

@ -29,9 +29,7 @@ from webnotes import _
def remove_attach():
"""remove attachment"""
import webnotes.utils.file_manager
fid = webnotes.form_dict.get('fid')
webnotes.utils.file_manager.remove_file(fid)
@webnotes.whitelist()