Merge branch 'master' into dev

This commit is contained in:
Anand Doshi 2012-07-13 16:47:21 +05:30
commit 09fd274753
20 changed files with 170 additions and 200 deletions

11
js/core.min.js vendored
View file

@ -130,8 +130,7 @@ wn.re_route={}
wn.route=function(){if(wn.re_route[window.location.hash]){var re_route_val=wn.get_route_str(wn.re_route[window.location.hash]);var cur_route_val=wn.get_route_str(wn._cur_route);if(decodeURIComponent(re_route_val)===decodeURIComponent(cur_route_val)){window.history.back();return;}else{window.location.hash=wn.re_route[window.location.hash];}}
wn._cur_route=window.location.hash;route=wn.get_route();switch(route[0]){case"List":wn.views.doclistview.show(route[1]);break;case"Form":if(route.length>3){route[2]=route.splice(2).join('/');}
wn.views.formview.show(route[1],route[2]);break;case"Report":wn.views.reportview.show(route[1],route[2]);break;case"Report2":wn.views.reportview2.show();break;default:wn.views.pageview.show(route[0]);}}
wn.get_route=function(route){if(!wn.boot){return[window.page_name];}
return $.map(wn.get_route_str(route).split('/'),function(r){return decodeURIComponent(r);});}
wn.get_route=function(route){return $.map(wn.get_route_str(route).split('/'),function(r){return decodeURIComponent(r);});}
wn.get_route_str=function(route){if(!route)
route=window.location.hash;if(route.substr(0,1)=='#')route=route.substr(1);if(route.substr(0,1)=='!')route=route.substr(1);return route;}
wn.set_route=function(){route=$.map(arguments,function(a){return encodeURIComponent(a)}).join('/');window.location.hash=route;wn.app.set_favicon();}
@ -188,13 +187,13 @@ if(me.show_filters){this.add_button('Show Filters',function(){me.filter_list.sho
if(me.no_toolbar||me.hide_toolbar){me.$w.find('.list-toolbar-wrapper').toggle(false);}},make_new_doc:function(new_doctype){new_doc(new_doctype);},make_filters:function(){this.filter_list=new wn.ui.FilterList({listobj:this,$parent:this.$w.find('.list-filters').toggle(true),doctype:this.doctype,filter_fields:this.filter_fields});},clear:function(){this.data=[];this.$w.find('.result-list').empty();this.$w.find('.result').toggle(true);this.$w.find('.no-result').toggle(false);this.start=0;},run:function(){var me=this;var a0=arguments[0];var a1=arguments[1];if(a0&&typeof a0=='function')
this.onrun=a0;if(a0&&a0.callback)
this.onrun=a0.callback;if(!a1&&!(a0&&a0.append))
this.start=0;me.set_working(true);wn.call({method:this.opts.method||'webnotes.widgets.query_builder.runquery',args:this.get_call_args(a0),callback:function(r){me.set_working(false);me.render_results(r)},no_spinner:this.opts.no_loading});},set_working:function(flag){this.$w.find('.img-load').toggle(flag);},get_call_args:function(opts){if(!this.method){this.query=this.get_query?this.get_query():this.query;this.add_limits();var args={query_max:this.query_max,as_dict:1}
args.simple_query=this.query;}else{var args={limit_start:this.start,limit_page_length:this.page_length}}
this.start=0;me.set_working(true);wn.call({method:this.opts.method||'webnotes.widgets.query_builder.runquery',args:this.get_call_args(a0),callback:function(r){me.set_working(false);me.render_results(r)},no_spinner:this.opts.no_loading});},set_working:function(flag){this.$w.find('.img-load').toggle(flag);},get_call_args:function(opts){if(!this.method){var query=this.get_query?this.get_query():this.query;query=this.add_limits(query);var args={query_max:this.query_max,as_dict:1}
args.simple_query=query;}else{var args={limit_start:this.start,limit_page_length:this.page_length}}
if(this.args)
$.extend(args,this.args)
if(this.get_args){$.extend(args,this.get_args(opts));}
return args;},render_results:function(r){if(this.start==0)this.clear();this.$w.find('.btn-more').toggle(false);if(r.message)r.values=r.message;if(r.values&&r.values.length){this.data=this.data.concat(r.values);this.render_list(r.values);this.update_paging(r.values);}else{if(this.start==0){this.$w.find('.result').toggle(false);this.$w.find('.no-result').toggle(true);}}
if(this.onrun)this.onrun();if(this.callback)this.callback(r);},render_list:function(values){var m=Math.min(values.length,this.page_length);for(var i=0;i<m;i++){this.render_row(this.add_row(),values[i],this,i);}},update_paging:function(values){if(values.length>=this.page_length){this.$w.find('.btn-more').toggle(true);this.start+=this.page_length;}},add_row:function(){return $('<div class="list-row">').appendTo(this.$w.find('.result-list')).get(0);},refresh:function(){this.run();},add_limits:function(){this.query+=' LIMIT '+this.start+','+(this.page_length+1);}});
if(this.onrun)this.onrun();if(this.callback)this.callback(r);},render_list:function(values){var m=Math.min(values.length,this.page_length);for(var i=0;i<m;i++){this.render_row(this.add_row(),values[i],this,i);}},update_paging:function(values){if(values.length>=this.page_length){this.$w.find('.btn-more').toggle(true);this.start+=this.page_length;}},add_row:function(){return $('<div class="list-row">').appendTo(this.$w.find('.result-list')).get(0);},refresh:function(){this.run();},add_limits:function(query){query+=' LIMIT '+this.start+','+(this.page_length+1);return query}});
/*
* lib/js/wn/ui/filters.js
*/
@ -268,7 +267,7 @@ wn.views.make_404=function(){var page=wn.container.add_page('404');$(page).html(
/*
* lib/js/wn/request.js
*/
wn.provide('wn.request');wn.request.url='index.cgi';wn.request.prepare=function(opts){if(opts.btn)$(opts.btn).set_working();if(opts.show_spinner)set_loading();if(opts.freeze)freeze();if(!opts.args.cmd){console.log(opts)
wn.provide('wn.request');wn.request.url='server.py';wn.request.prepare=function(opts){if(opts.btn)$(opts.btn).set_working();if(opts.show_spinner)set_loading();if(opts.freeze)freeze();if(!opts.args.cmd){console.log(opts)
throw"Incomplete Request";}}
wn.request.cleanup=function(opts,r){if(opts.btn)$(opts.btn).done_working();if(opts.show_spinner)hide_loading();if(opts.freeze)unfreeze();if(wn.boot&&wn.boot.sid&&wn.get_cookie('sid')!=wn.boot.sid){if(!wn.app.logged_out){msgprint('Session Expired. Logging you out');wn.app.logout();}
return;}

View file

@ -23,7 +23,7 @@
// My HTTP Request
wn.provide('wn.request');
wn.request.url = 'index.cgi';
wn.request.url = 'server.py';
// call execute serverside request
wn.request.prepare = function(opts) {

View file

@ -48,10 +48,10 @@ wn.route = function() {
}
wn.get_route = function(route) {
// route for web
if(!wn.boot) {
return [window.page_name];
}
// route for web [deprecated after cms2]
// if(!wn.boot) {
// return [window.page_name];
// }
// for app
return $.map(wn.get_route_str(route).split('/'),

View file

@ -238,13 +238,13 @@ wn.ui.Listing = Class.extend({
get_call_args: function(opts) {
// load query
if(!this.method) {
this.query = this.get_query ? this.get_query() : this.query;
this.add_limits();
var query = this.get_query ? this.get_query() : this.query;
query = this.add_limits(query);
var args={
query_max: this.query_max,
as_dict: 1
}
args.simple_query = this.query;
args.simple_query = query;
} else {
var args = {
limit_start: this.start,
@ -304,7 +304,8 @@ wn.ui.Listing = Class.extend({
refresh: function() {
this.run();
},
add_limits: function() {
this.query += ' LIMIT ' + this.start + ',' + (this.page_length+1);
add_limits: function(query) {
query += ' LIMIT ' + this.start + ',' + (this.page_length+1);
return query
}
});

View file

@ -374,7 +374,7 @@ wn.views.ListView = Class.extend({
// content
if(typeof opts.content=='function') {
opts.content(parent, data);
opts.content(parent, data, me);
}
else if(opts.content=='name') {
$(parent).append(repl('<a href="#!Form/%(doctype)s/%(name)s">%(name)s</a>', data));
@ -399,16 +399,7 @@ wn.views.ListView = Class.extend({
$(parent).append(data.when);
}
else if(opts.type=='bar-graph') {
args = {
percent: data[opts.content],
fully_delivered: (data[opts.content] > 99 ? 'bar-complete' : ''),
label: opts.label
}
$(parent).append(repl('<span class="bar-outer" style="width: 30px; float: right" \
title="%(percent)s% %(label)s">\
<span class="bar-inner %(fully_delivered)s" \
style="width: %(percent)s%;"></span>\
</span>', args));
this.render_bar_graph(parent, data, opts.content, opts.label);
}
else if(opts.type=='link' && opts.doctype) {
$(parent).append(repl('<a href="#!Form/'+opts.doctype+'/'
@ -502,6 +493,22 @@ wn.views.ListView = Class.extend({
if(!this.doclistview.can_delete) {
this.columns = $.map(this.columns, function(v, i) { if(v.content!='check') return v });
}
},
render_bar_graph: function(parent, data, field, label) {
var args = {
percent: data[field],
fully_delivered: (data[field] > 99 ? 'bar-complete' : ''),
label: label
}
$(parent).append(repl('<span class="bar-outer" style="width: 30px; float: right" \
title="%(percent)s% %(label)s">\
<span class="bar-inner %(fully_delivered)s" \
style="width: %(percent)s%;"></span>\
</span>', args));
},
render_icon: function(parent, icon_class, label) {
var icon_html = "<i class='%(icon_class)s' title='%(label)s'></i>";
$(parent).append(repl(icon_html, {icon_class: icon_class, label: label}));
}
});

View file

@ -98,9 +98,6 @@ class DocType:
if not os.path.exists(path + '.css'):
with open(path + '.css', 'w') as f:
pass
# web page
self.write_cms_page()
def get_from_files(self):
"""
@ -127,46 +124,4 @@ class DocType:
fpath = os.path.join(path, scrub(self.doc.name) + '.html')
if os.path.exists(fpath):
with open(fpath, 'r') as f:
self.doc.content = f.read()
def write_cms_page(self, force=False):
"""write cms page"""
import webnotes.cms
import os, codecs
from jinja2 import Template
if self.doc.web_page=='Yes' or force:
# doc will be dirty, so save it
_doc = self.doc.fields.copy()
# load from files
self.get_from_files()
fname = webnotes.cms.page_name(self.doc.name) + '.html'
# home page?
if self.doc.name==webnotes.cms.get_home_page('Guest'):
fname = 'index.html'
self.doc.web_page = 'Yes'
# save in public folder
if os.path.basename(os.path.abspath('.'))!='public':
fname = os.path.join('public', fname)
if not self.doc.title:
self.doc.title = self.doc.name
import startup.event_handlers
if hasattr(startup.event_handlers, 'get_web_header'):
self.doc.header = startup.event_handlers.get_web_header(self.doc.name)
if hasattr(startup.event_handlers, 'get_web_footer'):
self.doc.footer = startup.event_handlers.get_web_footer(self.doc.name)
with codecs.open(fname, 'w', 'utf-8') as page:
with open(os.path.join(os.path.dirname(webnotes.cms.__file__),
'template.html'), 'r') as template:
t = Template(template.read())
page.write(t.render(self.doc.fields))
# back to original doc
self.doc.fields = _doc
self.doc.content = f.read()

View file

@ -3,9 +3,9 @@
# These values are common in all dictionaries
{
'creation': '2012-04-02 16:01:07',
'creation': '2012-05-10 13:55:07',
'docstatus': 0,
'modified': '2012-05-07 12:17:01',
'modified': '2012-07-12 11:37:24',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
@ -99,15 +99,6 @@
'label': u'Title'
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'web_page',
'fieldtype': u'Select',
'label': u'Web Page',
'options': u'No\nYes'
},
# DocField
{
'doctype': u'DocField',

View file

@ -3,9 +3,9 @@
# These values are common in all dictionaries
{
'creation': '2012-05-01 17:10:24',
'creation': '2012-06-14 15:07:25',
'docstatus': 0,
'modified': '2012-05-09 10:17:33',
'modified': '2012-07-09 15:37:50',
'modified_by': u'Administrator',
'owner': u'Administrator'
},

View file

@ -38,7 +38,7 @@ class HTTPRequest:
if self.domain and self.domain.startswith('www.'):
self.domain = self.domain[4:]
webnotes.remote_ip = webnotes.get_env_vars('REMOTE_ADDR')
webnotes.remote_ip = webnotes.get_env_vars('REMOTE_ADDR')
# load cookies
webnotes.cookie_manager = CookieManager()

View file

@ -1,11 +1,3 @@
def page_name(title):
"""truncated page name"""
import re
name = title.lower()
name = re.sub('[~!@#$%^&*()<>,."\']', '', name)
return '-'.join(name.split()[:4])
def get_home_page(user=None):
"""get home page for user"""
if not user:

View file

@ -43,7 +43,7 @@ rss_item = u"""
<description>%(content)s</description>
<link>%(link)s</link>
<guid>%(name)s</guid>
<pubDate>%(modified)s</pubDate>
<pubDate>%(published)s</pubDate>
</item>"""
def generate():
@ -54,26 +54,29 @@ def generate():
host = (os.environ.get('HTTPS') and 'https://' or 'http://') + os.environ.get('HTTP_HOST')
items = ''
modified = None
for blog in webnotes.conn.sql("""select name, title, content, modified, page_name
from tabBlog
where ifnull(published,0)=1
order by modified desc limit 100""", as_dict=1):
blog_list = webnotes.conn.sql("""\
select
cache.name as name, cache.modified as modified,
blog.creation as published, blog.title as title
from `tabWeb Cache` cache, `tabBlog` blog
where cache.doc_type = 'Blog' and blog.page_name = cache.name
order by published desc, modified desc, name asc limit 100""", as_dict=1)
import website.blog
for blog in blog_list:
blog['link'] = host + '/' + blog['name'] + '.html'
blog['content'] = website.blog.get_blog_content(blog['name'])
blog['link'] = host + '/' + blog['page_name'] + '.html'
blog['content'] = scrub(blog['content'][:1000] or '')
if not modified:
modified = blog['modified']
items += rss_item % blog
modified = max((blog['modified'] for blog in blog_list))
ws = Document('Website Settings', 'Website Settings')
return (rss % {
'title': ws.title_prefix,
'description': ws.description or (ws.title_prefix + ' Blog'),
'modified': modified,
'items': items,
'link': host + '/blog.html'
}).encode('utf-8', 'ignore')
def scrub(txt):
return txt.replace('<', '&lt;').replace('>', '&gt;')
'title': ws.title_prefix,
'description': ws.description or (ws.title_prefix + ' Blog'),
'modified': modified,
'items': items,
'link': host + '/blog.html'
}).encode('utf-8', 'ignore')

View file

@ -17,11 +17,10 @@ def make():
def make_web_core():
"""make index.html, wn-web.js, wn-web.css, sitemap.xml and rss.xml"""
# index.html
from webnotes.model.code import get_obj
#from webnotes.model.code import get_obj
import webnotes
home_page = webnotes.cms.get_home_page('Guest')
get_obj('Page', home_page).write_cms_page()
# js/wn-web.js and css/wn-web.css
write_web_js_css(home_page)

View file

@ -42,16 +42,15 @@ def generate(domain):
page_list = []
if domain:
# list of all Guest pages (static content)
for r in webnotes.conn.sql("""SELECT distinct t1.name, t1.modified
FROM tabPage t1, `tabPage Role` t2
WHERE t1.name = t2.parent
and t2.role = 'Guest'
and t1.web_page = 'Yes'
ORDER BY modified DESC"""):
page_url = os.path.join(domain, urllib.quote(r[0]) + '.html')
site_map += link_xml % (page_url, r[1].strftime('%Y-%m-%d'))
# list of all pages in web cache
pages = webnotes.conn.sql("""\
select name, `modified`
from `tabWeb Cache`
order by modified desc""")
for p in pages:
page_url = os.path.join(domain, urllib.quote(p[0]) + '.html')
modified = p[1].strftime('%Y-%m-%d')
site_map += link_xml % (page_url, modified)
return frame_xml % site_map

View file

@ -1,43 +0,0 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
<meta name="generator" content="wnframework">
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
<link rel="icon" href="images/favicon.ico" type="image/x-icon">
<script type="text/javascript" src="js/lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="js/all-web.js"></script>
<script type="text/javascript" src="js/wn-web.js"></script>
<link type="text/css" rel="stylesheet" href="css/all-web.css">
<link type="text/css" rel="stylesheet" href="css/wn-web.css">
{% if script %}
<script>
window.page_name = "{{ name }}";
$(document).bind('app_ready', function() {
var _page = new wn.views.Page(window.page_name);
// page script
{{ script }}
// trigger onload
_page.trigger('onload');
// activate page
wn.container.change_to(window.page_name);
});
</script>
{% endif %}
{% if style %}
<style>{{ style }}</style>
{% endif %}
</head>
<body>
<header>{{ header }}</header>
<div id="body_div">
<div class="content" id="page-{{ name }}" style="display: block;">
{{ content }}
</div>
</div>
<footer>{{ footer }}</footer>
</body>

View file

@ -35,7 +35,7 @@ type_map = {
,'float': ('decimal', '18,6')
,'check': ('int', '1')
,'small text': ('text', '')
,'long text': ('text', '')
,'long text': ('longtext', '')
,'code': ('text', '')
,'text editor': ('text', '')
,'date': ('date', '')

View file

@ -311,4 +311,4 @@ def peval_doclist(txt):
else:
return eval(txt)
return uncommonify_doclist(eval(txt))
return uncommonify_doclist(eval(txt))

View file

@ -283,7 +283,7 @@ def global_date_format(date):
if isinstance(date, basestring):
date = getdate(date)
return date.strftime('%d') + ' ' + month_name_full[int(date.strftime('%m'))] \
return cstr(cint(date.strftime('%d'))) + ' ' + month_name_full[int(date.strftime('%m'))] \
+ ' ' + date.strftime('%Y')
@ -655,6 +655,24 @@ def unesc(s, esc_chars):
esc_str = '\\' + c
s = s.replace(esc_str, c)
return s
def strip_html(text):
"""
removes anything enclosed in and including <>
"""
import re
return re.compile(r'<.*?>').sub('', text)
def escape_html(text):
html_escape_table = {
"&": "&amp;",
'"': "&quot;",
"'": "&apos;",
">": "&gt;",
"<": "&lt;",
}
return "".join(html_escape_table.get(c,c) for c in text)
def get_doctype_label(dt=None):
"""
@ -698,3 +716,47 @@ def get_system_managers_list():
p.name not in ('Administrator', 'Guest')""", as_list=1)
return [sysman[0] for sysman in system_managers_list]
def pretty_date(iso_datetime):
"""
Takes an ISO time and returns a string representing how
long ago the date represents.
Ported from PrettyDate by John Resig
"""
if not iso_datetime: return ''
from datetime import datetime
import math
if isinstance(iso_datetime, basestring):
iso_datetime = datetime.strptime(iso_datetime, '%Y-%m-%d %H:%M:%S')
now_dt = datetime.strptime(now(), '%Y-%m-%d %H:%M:%S')
dt_diff = now_dt - iso_datetime
# available only in python 2.7+
# dt_diff_seconds = dt_diff.total_seconds()
dt_diff_seconds = dt_diff.days * 86400.0 + dt_diff.seconds
dt_diff_days = math.floor(dt_diff_seconds / 86400.0)
# differnt cases
if dt_diff_seconds < 60.0:
return 'just now'
elif dt_diff_seconds < 120.0:
return '1 minute ago'
elif dt_diff_seconds < 3600.0:
return '%s minutes ago' % cint(math.floor(dt_diff_seconds / 60.0))
elif dt_diff_seconds < 7200.0:
return '1 hour ago'
elif dt_diff_seconds < 86400.0:
return '%s hours ago' % cint(math.floor(dt_diff_seconds / 3600.0))
elif dt_diff_days == 1.0:
return 'Yesterday'
elif dt_diff_days < 7.0:
return '%s days ago' % cint(dt_diff_days)
elif dt_diff_days < 31.0:
return '%s week(s) ago' % cint(math.ceil(dt_diff_days / 7.0))
elif dt_diff_days < 365.0:
return '%s months ago' % cint(math.ceil(dt_diff_days / 30.0))
else:
return 'more than %s year(s) ago' % cint(math.floor(dt_diff_days / 365.0))

View file

@ -42,10 +42,10 @@ def get_comments(doctype=None, docname=None, limit=5):
webnotes.response['n_comments'], webnotes.response['comment_list'] = nc, cl
@webnotes.whitelist(allow_guest=True)
def add_comment():
def add_comment(args=None):
"""add a new comment"""
import time
args = webnotes.form_dict
if not args: args = webnotes.form_dict
if args.get('comment'):
from webnotes.model.doc import Document
@ -60,6 +60,8 @@ def add_comment():
import startup.event_handlers
if hasattr(startup.event_handlers, 'comment_added'):
startup.event_handlers.comment_added(cmt)
return cmt.fields
@webnotes.whitelist()
def remove_comment():

View file

@ -115,7 +115,7 @@ def add_match_conditions(q, tl, ur, ud):
q = q[0] + condition_st + '(' + ' OR '.join(sl) + ') ' + condition_end + q[1]
else:
q = q + condition_st + '(' + ' OR '.join(sl) + ')'
return q
# execute server-side script from Search Criteria
@ -346,3 +346,17 @@ def runquery_csv():
out['type'] = 'csv'
out['doctype'] = rep_name
def add_limit_to_query(query, args):
"""
Add limit condition to query
can be used by methods called in listing to add limit condition
"""
if args.get('limit_page_length'):
query += """
limit %(limit_start)s, %(limit_page_length)s"""
import webnotes.utils
args['limit_start'] = webnotes.utils.cint(args.get('limit_start'))
args['limit_page_length'] = webnotes.utils.cint(args.get('limit_page_length'))
return query, args

39
wnf.py
View file

@ -70,24 +70,6 @@ def search_replace_with_prompt(fpath, txt1, txt2):
f.write(''.join(tmp))
print colored('Updated', 'green')
def create_cms_files():
from webnotes.model.code import get_obj
os.system('rm public/login-page.html')
# rewrite pages
ws = get_obj('Website Settings')
ws.rewrite_pages()
ss = get_obj('Style Settings')
ss.validate()
ss.doc.save()
ss.on_update()
# create login-page.html if it doesnt exist by copying index.html
if not os.path.exists('public/login-page.html') and os.path.exists('public/index.html'):
os.system('cp public/index.html public/login-page.html')
# change owner of files
os.system('chown -R apache:apache *')
def pull(remote, branch):
os.system('git pull %s %s' % (remote, branch))
os.system('cd lib && git pull %s %s' % (remote, branch))
@ -108,6 +90,11 @@ def update_erpnext(remote='origin', branch='master'):
# apply latest patches
apply_latest_patches()
import webnotes.modules.patch_handler
for l in webnotes.modules.patch_handler.log_list:
if "failed: STOPPED" in l:
return
# sync all
sync_all()
@ -124,8 +111,10 @@ def setup_options():
# build
parser.add_option("-b", "--build", default=False, action="store_true",
help="minify + concat js files")
parser.add_option("--cms", default=False, action="store_true",
help="take a dump of website pages, js and css")
parser.add_option("--build_web_cache", default=False, action="store_true",
help="build web cache")
parser.add_option("--domain", metavar="DOMAIN",
help="store domain in Website Settings", nargs=1)
@ -303,11 +292,7 @@ def run():
elif options.update:
update_erpnext(options.update[0], options.update[1])
if options.cms: create_cms_files()
elif options.cms:
create_cms_files()
elif options.cleanup_data:
from utilities import cleanup_data
cleanup_data.run()
@ -316,6 +301,10 @@ def run():
webnotes.conn.set_value('Website Settings', None, 'subdomain', options.domain)
webnotes.conn.commit()
print "Domain set to", options.domain
elif options.build_web_cache:
import website.web_cache
website.web_cache.refresh_cache(True)
# print messages
if webnotes.message_log: