Merge branch 'master' into production

This commit is contained in:
Nabin Hait
2012-12-18 13:49:07 +05:30
41 changed files with 519 additions and 489 deletions

View File

@@ -6,6 +6,8 @@ install_docs = [
import webnotes
max_tickets_per_hour = 200
@webnotes.whitelist(allow_guest=True)
def send_message():
from webnotes.model.doc import Document
@@ -17,15 +19,21 @@ def send_message():
d.raised_by = webnotes.form_dict.get('sender')
if not d.description:
webnotes.msgprint('Please write something', raise_exception=True)
webnotes.response["message"] = 'Please write something'
return
if not d.raised_by:
webnotes.msgprint('Please give us your email id so that we can write back to you', raise_exception=True)
webnotes.response["message"] = 'Email Id Required'
return
# make lead or contact
# guest method, cap max writes per hour
if webnotes.conn.sql("""select count(*) from `tabSupport Ticket`
where TIMEDIFF(NOW(), modified) < '01:00:00'""")[0][0] > max_tickets_per_hour:
webnotes.response["message"] = "Sorry: we believe we have received an unreasonably high number of requests of this kind. Please try later"
return
d.save()
webnotes.msgprint('Thank you!')
webnotes.response["message"] = 'Thank You'
def get_site_address():
from webnotes.utils import get_request_site_address

View File

@@ -9,8 +9,7 @@ import website.utils
def get_blog_list(args=None):
"""
args = {
'limit_start': 0,
'limit_page_length': 10,
'start': 0,
}
"""
import webnotes
@@ -24,11 +23,9 @@ def get_blog_list(args=None):
comment_doctype='Blog' and comment_docname=`tabBlog`.name) as comments
from `tabBlog`
where ifnull(published,0)=1
order by creation desc, name asc"""
from webnotes.widgets.query_builder import add_limit_to_query
query, args = add_limit_to_query(query, args)
order by creation desc, name asc
limit %s, 5""" % args.start
result = webnotes.conn.sql(query, args, as_dict=1)
# strip html tags from content
@@ -41,38 +38,6 @@ def get_blog_list(args=None):
if not res['content']:
res['content'] = website.utils.get_html(res['page_name'])
res['content'] = split_blog_content(res['content'])
res['content'] = res['content'][:1000]
return result
@webnotes.whitelist(allow_guest=True)
def get_recent_blog_list(args=None):
"""
args = {
'limit_start': 0,
'limit_page_length': 5,
'name': '',
}
"""
import webnotes
if not args: args = webnotes.form_dict
query = """\
select name, page_name, title, left(content, 100) as content
from tabBlog
where ifnull(published,0)=1 and
name!=%(name)s order by creation desc"""
from webnotes.widgets.query_builder import add_limit_to_query
query, args = add_limit_to_query(query, args)
result = webnotes.conn.sql(query, args, as_dict=1)
# strip html tags from content
import webnotes.utils
for res in result:
res['content'] = webnotes.utils.strip_html(res['content'])
return result

View File

@@ -4,6 +4,25 @@
from __future__ import unicode_literals
import webnotes
@webnotes.whitelist(allow_guest=True)
def get_product_info(item_code):
"""get product price / stock info"""
price_list = webnotes.conn.get_value("Item", item_code, "website_price_list")
warehouse = webnotes.conn.get_value("Item", item_code, "website_warehouse")
if warehouse:
in_stock = webnotes.conn.sql("""select actual_qty from tabBin where
item_code=%s and warehouse=%s""", (item_code, warehouse))
if in_stock:
in_stock = in_stock[0][0] > 0 and 1 or 0
else:
in_stock = -1
return {
"price": price_list and webnotes.conn.sql("""select ref_rate, ref_currency from
`tabItem Price` where parent=%s and price_list_name=%s""",
(item_code, price_list), as_dict=1) or [],
"stock": in_stock
}
@webnotes.whitelist(allow_guest=True)
def get_product_list(args=None):
"""

View File

@@ -6,4 +6,8 @@
.comment-content {
margin-left: 20px;
}
input {
width: 240px;
}
</style>

View File

@@ -5,6 +5,7 @@
}
.layout-wrapper {
background-color: #fff;
padding: 10px;
box-shadow: 1px 1px 3px 3px #ccc;
font-size: 12px;

View File

@@ -1,34 +1,12 @@
<style>
.product-page-content {
margin-left: -20px;
}
.item-main-image {
max-width: 100%;
}
.web-long-description {
font-size: 18px;
line-height: 200%;
}
.product-page-content {
float: left;
}
/* product page image css */
.product-page-content img {
max-width: 100%;
}
/* similar products listing */
.similar-products .img-area img {
max-width: 55px;
max-height: 55px;
}
.similar-products .img-area {
float: left;
width: 30%;
margin-top: 0.3em;
}
.similar-product-description {
float: left;
width: 70%;
}
.similar-product-description span {
font-size: 12px;
}
</style>

View File

@@ -2,7 +2,6 @@
{% block javascript %}
{% include "js/blog_page.js" %}
{% include "js/blog_subscribe.js" %}
{% endblock %}
{% block css %}
@@ -28,15 +27,32 @@
<div class="blog-comments">
{% if not comment_list %}
<div class="no-result help hide">
<div class="alert no-comment">
<p>Be the first one to comment</p>
<br />
</div>
{% endif %}
{% include 'html/comment.html' %}
</div>
<button class="btn add-comment">Add Comment</button>
<div><button class="btn add-comment">Add Comment</button></div>
<div style="display: none; margin-top: 10px;"
id="comment-form" class="well">
<div class="alert" style="display:none;"></div>
<form>
<p>
<input name="comment_by_fullname" placeholder="Your Name" />
</p>
<p>
<input name="comment_by" placeholder="Your Email Id" />
</p>
<p>
<textarea name="comment" placeholder="Comment" />
</textarea>
</p>
<p>
<button class="btn btn-info" id="submit-comment">Submit</button>
</form>
</div>
</div>
</div>
</div>

View File

@@ -5,28 +5,12 @@
{% block header %}
{{ super() }}
<script>
window.page_name = "{{ name }}";
$(document).bind('app_ready', function() {
var _page = new wn.views.Page(window.page_name);
// page script
{% block javascript %}
{% endblock %}
// trigger onload
_page.trigger('onload');
// activate page
wn.container.change_to(window.page_name);
});
{% block javascript %}
{% endblock %}
</script>
{% block css %}
{% if insert_style %}
{% if insert_style %}
<style>{{ css }}</style>
{% endif %}
{% endblock %}
{% endblock %}

View File

@@ -0,0 +1 @@
{% extends "html/page.html" %}

View File

@@ -19,30 +19,48 @@
{% block content %}
<div class="layout-wrapper layout-wrapper-background">
<div class="web-content" id="content-product-{{ name }}">
<div class="layout-main-section">
<div class="layout-main" style="padding: 30px;">
{% include 'html/product_search.html' %}
<h1>{{ item_name }}</h1>
<div class="product-page-content">
<br><br>
<div class="span6">
{% if website_image %}
<image src="files/{{ website_image }}" />
<image class="item-main-image" src="files/{{ website_image }}" />
{% else %}
<div class="img-area"></div>
<span style="font-size: 11px">This is an auto-generated Image</span>
{% endif %}
<br><br>
<div class="web-long-description">
{{ web_description_html }}
</div>
<div class="span3">
<div class="item-price hide">
<p>Price:</p>
</div>
<div class="item-stock"></div>
</div>
<div class="clearfix"></div>
<div class="span9">
<h3>Product Description</h3>
<div>
{{ web_long_description or web_short_description }}
</div>
<hr>
{% if obj.doclist.get({"doctype":"Item Website Specification"}) %}
<h3>Specifications</h3>
<table class="table table-striped table-bordered" style="width: 100%">
{% for d in obj.doclist.get(
{"doctype":"Item Website Specification"}) %}
<tr>
<td>{{ d.label }}</td>
<td>{{ d.description }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
<div class="clearfix"></div>
</div>
</div>
<div class="layout-side-section">
<h4>More Categories</h4>
<div class="more-categories"></div>
<br>
<h4>Similar Products</h4>
<div class="similar-products"></div>
</div>
<div style="clear: both"></div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,9 @@
<div class="pull-right">
<form class="form-search">
<div class="input-append">
<input type="text" class="span2 search-query" id="product-search">
<button class="btn"><i class="icon-search"></i></button>
</div>
</form>
</div>
<div class="clearfix"></div>

View File

@@ -15,29 +15,54 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// js inside blog page
wn.pages['{{ name }}'].onload = function(wrapper) {
erpnext.blog_list = new wn.ui.Listing({
parent: $(wrapper).find('#blog-list').get(0),
method: 'website.helpers.blog.get_blog_list',
hide_refresh: true,
no_toolbar: true,
render_row: function(parent, data) {
if(!data.comments) {
data.comment_text = 'No comments yet.'
} else if (data.comments===1) {
data.comment_text = '1 comment.'
$(document).ready(function() {
// make list of blogs
blog.get_list();
$("#next-page").click(function() {
blog.get_list();
})
});
var blog = {
start: 0,
get_list: function() {
$.ajax({
method: "GET",
url: "server.py",
data: {
cmd: "website.helpers.blog.get_blog_list",
start: blog.start
},
dataType: "json",
success: function(data) {
blog.render(data.message);
}
});
},
render: function(data) {
var $wrap = $("#blog-list");
$.each(data, function(i, b) {
// comments
if(!b.comments) {
b.comment_text = 'No comments yet.'
} else if (b.comments===1) {
b.comment_text = '1 comment.'
} else {
data.comment_text = data.comments + ' comments.'
b.comment_text = b.comments + ' comments.'
}
if(data.content && data.content.length==1000) {
data.content += repl('... <a href="%(page_name)s.html">(read on)</a>', data);
}
parent.innerHTML = repl('<h2><a href="%(page_name)s.html">%(title)s</a></h2>\
$(repl('<h2><a href="%(page_name)s.html">%(title)s</a></h2>\
<div class="help">%(comment_text)s</div>\
%(content)s<br /><br />', data);
},
page_length: 10
});
erpnext.blog_list.run();
%(content)s<br />\
<p><a href="%(page_name)s">Read with comments...</a></p>\
<hr /><br />', b)).appendTo($wrap);
});
blog.start += data.length;
if(!data.length) {
$("#next-page").toggle(false)
.parent().append("<div class='alert'>Nothing more to show.</div>");
}
}
}

View File

@@ -16,166 +16,61 @@
// js inside blog page
wn.provide('erpnext.blog');
wn.pages['{{ name }}'].onload = function(wrapper) {
erpnext.blog.wrapper = wrapper;
$(document).ready(function() {
var n_comments = $(".comment-row").length;
// sidebar
//erpnext.blog.render_recent_list(wrapper);
// unhide no-result if no comments found
erpnext.blog.toggle_no_result(wrapper);
// bind add comment button to comment dialog
erpnext.blog.make_comment_dialog(wrapper);
// hide add comment button after 50 comments
erpnext.blog.toggle_add_comment_btn(wrapper);
}
erpnext.blog.adjust_page_height = function(wrapper) {
if (!wrapper) { wrapper = erpnext.blog.wrapper; }
if (!wrapper) { return; }
// adjust page height based on sidebar height
var $main_page = $(wrapper).find('.layout-main-section');
var $sidebar = $(wrapper).find('.layout-side-section');
if ($sidebar.height() > $main_page.height()) {
$main_page.height($sidebar.height());
if(n_comments) {
$(".no_comment").toggle(false);
}
}
erpnext.blog.render_recent_list = function(wrapper) {
if (!wrapper) { wrapper = erpnext.blog.wrapper; }
if (!wrapper) { return; }
wrapper.recent_list = new wn.ui.Listing({
parent: $(wrapper).find('.recent-posts'),
no_toolbar: true,
method: 'website.helpers.blog.get_recent_blog_list',
get_args: function() {
return { name: '{{ name }}' }
},
hide_refresh: true,
render_row: function(parent, data) {
if(data.content && data.content.length>=100) data.content += '...';
parent.innerHTML = repl('<div style="font-size: 80%">\
<a href="%(page_name)s.html">%(title)s</a>\
<div class="comment">%(content)s</div><br></div>', data);
// adjust page height depending on sidebar height
erpnext.blog.adjust_page_height(wrapper);
},
page_length: 5,
});
wrapper.recent_list.run();
}
erpnext.blog.toggle_no_result = function(wrapper) {
if (!wrapper) { wrapper = erpnext.blog.wrapper; }
if (!wrapper) { return; }
var $blog_comments = $(wrapper).find('.blog-comments');
var $comment_rows = $blog_comments.find('.comment-row');
var $no_result = $blog_comments.find('.no-result');
if ($comment_rows.length == 0) {
$no_result.removeClass('hide');
} else {
$no_result.addClass('hide');
if(n_comments > 50) {
$(".add-comment").toggle(false)
.parent().append("<div class='alert'>Comments are closed.</div>")
}
}
erpnext.blog.make_comment_dialog = function(wrapper) {
if (!wrapper) { wrapper = erpnext.blog.wrapper; }
if (!wrapper) { return; }
var $comment_btn = $(wrapper).find('button.add-comment');
$comment_btn.click(function() {
if(!erpnext.blog.comment_dialog) {
var d = new wn.ui.Dialog({
title: 'Add Comment',
fields: [
{
fieldname: 'comment_by_fullname', label: 'Your Name',
reqd: 1, fieldtype: 'Data'
},
{
fieldname: 'comment_by', label: 'Email Id',
reqd: 1, fieldtype: 'Data'
},
{
fieldname: 'comment', label: 'Comment',
reqd: 1, fieldtype: 'Text'
},
{
fieldname: 'post_comment', label: 'Post Comment',
fieldtype: 'Button'
},
],
});
erpnext.blog.comment_dialog = d;
$(".add-comment").click(function() {
$("#comment-form").toggle();
$("#comment-form input, #comment-form, textarea").val("");
})
$("#submit-comment").click(function() {
var args = {
comment_by_fullname: $("[name='comment_by_fullname']").val(),
comment_by: $("[name='comment_by']").val(),
comment: $("[name='comment']").val(),
cmd: "website.helpers.blog.add_comment",
comment_doctype: "Blog",
comment_docname: "{{ name }}",
page_name: "{{ page_name }}"
}
erpnext.blog.comment_dialog.fields_dict.post_comment
.input.onclick = function() {
erpnext.blog.add_comment(wrapper);
$("#comment-form .alert").toggle(false);
if(!args.comment_by_fullname || !args.comment_by || !args.comment) {
$("#comment-form .alert")
.html("All fields are necessary to submit the comment.")
.toggle(true);
return false;
}
erpnext.blog.comment_dialog.show();
});
}
erpnext.blog.add_comment = function(wrapper) {
var args = erpnext.blog.comment_dialog.get_values();
if(!args) return;
args.comment_doctype = 'Blog';
args.comment_docname = '{{ name }}';
args.page_name = '{{ page_name }}';
wn.call({
method: 'website.helpers.blog.add_comment',
args: args,
btn: this,
callback: function(r) {
if(!r.exc) {
erpnext.blog.add_comment_to_page(wrapper, r.message);
erpnext.blog.comment_dialog.hide();
$.ajax({
method: "POST",
url: "server.py",
data: args,
dataType: "json",
success: function(data) {
if(data.exc) {
$("#comment-form .alert")
.html(data.exc)
.toggle(true)
} else {
$(data.message).appendTo(".blog-comments");
$(".no_comment").toggle(false);
$(".add-comment").toggle(false);
$("#comment-form")
.replaceWith("<div class='alert'>Thank you for your comment!</div>")
}
}
}
});
}
erpnext.blog.add_comment_to_page = function(wrapper, comment) {
$blog_comments = $(wrapper).find('.blog-comments');
$comment_rows = $blog_comments.find('.comment-row');
if ($comment_rows.length) {
$blog_comments.append(comment);
} else {
$blog_comments.append(comment);
}
erpnext.blog.toggle_no_result(wrapper);
erpnext.blog.toggle_add_comment_btn(wrapper);
}
erpnext.blog.toggle_add_comment_btn = function(wrapper) {
var $wrapper = $(wrapper);
if ($wrapper.find('.blog-comments .comment-row').length > 50) {
var $comment_btn = $wrapper.find('button.add-comment');
$comment_btn.addClass('hide');
})
// show comments are close
$wrapper.find('.blog-comments').append("\
<div class=\"help\"> \
<p>Comments Closed</p> \
<br /> \
</div>");
}
}
return false;
})
})

View File

@@ -1,13 +1,13 @@
wn.provide('erpnext.login');
var login = {};
$(document).ready(function(wrapper) {
$('#login_btn').click(erpnext.login.doLogin)
$('#login_btn').click(login.do_login)
$('#password').keypress(function(ev){
if(ev.which==13 && $('#password').val()) {
$('form').submit(function() {
erpnext.login.doLogin();
login.do_login();
return false;
});
}
@@ -16,54 +16,60 @@ $(document).ready(function(wrapper) {
})
// Login
erpnext.login.doLogin = function(){
login.do_login = function(){
var args = {};
args['usr']=$("#login_id").val();
args['pwd']=$("#password").val();
if(!args.usr || !args.pwd) {
msgprint("Sorry, you can't login if you don't enter both the email id and password.")
login.set_message("Both login and password required.");
}
$('#login_btn').set_working();
$('#login_message').empty();
$('#login_btn').attr("disabled", "disabled");
$('#login_message').toggle(false);
$.ajax({
type: "POST",
url: "server.py",
data: {cmd:"login", usr:args.usr, pwd: args.pwd},
dataType: "json",
success: function(data) {
$('#login_btn').attr("disabled", false);
if(data.message=="Logged In") {
window.location.href = "app.html";
} else {
login.set_message(data.message);
}
}
})
$c("login", args, function(r, rtext) {
$('#login_btn').done_working();
if(r.message=="Logged In"){
window.location.href='app.html' + (get_url_arg('page')
? ('?page='+get_url_arg('page')) : '');
} else {
$i('login_message').innerHTML = '<span style="color: RED;">'
+(r.message)+'</span>';
}
});
return false;
}
erpnext.login.show_forgot_password = function(){
login.show_forgot_password = function(){
// create dialog
var d = new wn.ui.Dialog({
title:"Forgot Password",
fields: [
{'label':'Email Id', 'fieldname':'email_id', 'fieldtype':'Data', 'reqd':true},
{'label':'Email Me A New Password', 'fieldname':'run', 'fieldtype':'Button'}
]
});
var login_id = $("#login_id").val();
if(!login_id || !valid_email(login_id)) {
login.set_message("Please set your login id (which is your email where the password will be sent);");
return;
}
login.set_message("Sending email with new password...");
$("#forgot-password").remove();
$(d.fields_dict.run.input).click(function() {
var values = d.get_values();
if(!values) return;
wn.call({
method:'reset_password',
args: { user: values.email_id },
callback: function() {
d.hide();
}
})
$.ajax({
method: "POST",
url: "server.py",
data: {
cmd: "reset_password",
user: login_id
},
success: function(data) {
login.set_message("A new password has been sent to your email id.", "GREEN");
}
})
d.show();
}
login.set_message = function(message, color) {
$('#login_message').html(message).toggle(true);
}

View File

@@ -14,79 +14,30 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
{% include "js/product_category.js" %}
wn.pages['{{ name }}'].onload = function(wrapper) {
wrapper.product_group = "{{ item_group }}";
wrapper.product_name = "{{ name }}";
erpnext.products.make_product_categories(wrapper);
erpnext.products.make_similar_products(wrapper);
// if website image missing, autogenerate one
var $img = $(wrapper).find('.product-page-content .img-area');
if ($img && $img.length > 0) {
$img.append(wn.dom.placeholder(160, "{{ item_name }}"));
}
erpnext.products.adjust_page_height(wrapper);
}
erpnext.products.adjust_page_height = function(wrapper) {
if (!wrapper) { wrapper = erpnext.products.wrapper; }
if (!wrapper) { return; }
// adjust page height based on sidebar height
var $main_page = $(wrapper).find('.layout-main-section');
var $sidebar = $(wrapper).find('.layout-side-section');
if ($sidebar.height() > $main_page.height()) {
$main_page.height($sidebar.height());
}
}
erpnext.products.make_similar_products = function(wrapper) {
if (!wrapper) { wrapper = erpnext.products.wrapper; }
if (!wrapper) { return; }
// similar products
wrapper.similar = new wn.ui.Listing({
parent: $(wrapper).find('.similar-products').get(0),
hide_refresh: true,
page_length: 5,
method: 'website.helpers.product.get_similar_product_list',
get_args: function() {
return {
product_group: wrapper.product_group,
product_name: wrapper.product_name
}
$(document).ready(function() {
$.ajax({
method: "GET",
url:"server.py",
dataType: "json",
data: {
cmd: "website.helpers.product.get_product_info",
item_code: "{{ name }}"
},
render_row: function(parent, data) {
if (!data.web_short_description) {
data.web_short_description = data.description;
success: function(data) {
if(data.message) {
if(data.message.price) {
$("<h4>").html(data.message.price[0].ref_currency + " "
+ data.message.price[0].ref_rate).appendTo(".item-price");
$(".item-price").toggle(true);
}
if(data.message.stock==0) {
$(".item-stock").html("<div class='help'>Not in stock</div>")
}
else if(data.message.stock==1) {
$(".item-stock").html("<div style='color: green'>\
<i class='icon-check'></i> Available (in stock)</div>")
}
}
if(data.web_short_description.length > 100) {
data.web_short_description =
data.web_short_description.substr(0,100) + '...';
}
parent.innerHTML = repl('\
<a href="%(page_name)s.html"><div class="img-area"></div></a>\
<div class="similar-product-description">\
<h5><a href="%(page_name)s.html">%(item_name)s</a></h5>\
<span>%(web_short_description)s</span>\
</div>\
<div style="clear:both"></div>', data);
if(data.website_image) {
$(parent).find('.img-area').append(repl(
'<img src="files/%(website_image)s" />', data))
} else {
$(parent).find('.img-area').append(wn.dom.placeholder(55,
data.item_name));
}
// adjust page height, if sidebar height keeps increasing
erpnext.products.adjust_page_height(wrapper);
}
});
wrapper.similar.run();
}
})
})

View File

@@ -2,7 +2,6 @@
{% block javascript %}
{% include "js/blog.js" %}
{% include "js/blog_subscribe.js" %}
{% endblock %}
{% block css %}
@@ -18,9 +17,12 @@
<div class="layout-main">
<h1>Blog</h1>
<br>
<div id="blog-list">
<div id="blog-list" style="min-height: 400px;">
<!-- blog list will be generated dynamically -->
</div>
<div style="text-align: center;">
<button id="next-page" class="btn">More...</button>
</div>
</div>
</div>
</div>

View File

@@ -14,6 +14,7 @@
{% block body %}
<div id='login_wrapper'>
<div class='layout-wrapper layout-main'>
<p id="login_message" class="alert" style="display: none;"></p>
<h3><i class="icon-lock" style="margin-top: 7px"></i> Login</h3>
<form autocomplete="on">
<table border="0" class="login-box">
@@ -33,15 +34,12 @@
class="btn btn-small btn-primary">Login</button>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td id="login_message">&nbsp;</td>
</tr>
</tbody>
</table>
</form>
<p style="text-align: center"><span class="link_type"
onclick="erpnext.login.show_forgot_password()">Forgot Password</span></p>
<br>
<p style="text-align: center"><a id="forgot-password"
onclick="return login.show_forgot_password()">Forgot Password</a></p>
</div>
<div class="login-footer">
<a href="index.html">Home</a> |

View File

@@ -33,6 +33,10 @@ page_map = {
'Item': webnotes._dict({
"template": 'html/product_page.html',
"condition_field": "show_in_website",
}),
'Item Group': webnotes._dict({
"template": "html/product_group.html",
"condition_field": "show_in_website"
})
}
@@ -152,13 +156,14 @@ def get_template_pages():
def get_doc_fields(page_name):
doc_type, doc_name = get_source_doc(page_name)
obj = webnotes.get_obj(doc_type, doc_name)
obj = webnotes.get_obj(doc_type, doc_name, with_children=True)
if hasattr(obj, 'prepare_template_args'):
obj.prepare_template_args()
args = obj.doc.fields
args['template'] = page_map[doc_type].template
args['obj'] = obj
return args