Merge branch 'master' of github.com:webnotes/wnframework into edge
This commit is contained in:
commit
da7f841b2e
21 changed files with 2734 additions and 234 deletions
|
|
@ -1,8 +1,14 @@
|
|||
cur_frm.cscript.onload = function(doc) {
|
||||
if(!cur_frm.roles_editor && has_common(user_roles, ["Administrator", "System Manager"])) {
|
||||
var role_area = $('<div style="min-height: 300px">')
|
||||
.appendTo(cur_frm.fields_dict.roles_html.wrapper);
|
||||
cur_frm.roles_editor = new wn.RoleEditor(role_area);
|
||||
if(has_common(user_roles, ["Administrator", "System Manager"])) {
|
||||
if(!cur_frm.roles_editor) {
|
||||
var role_area = $('<div style="min-height: 300px">')
|
||||
.appendTo(cur_frm.fields_dict.roles_html.wrapper);
|
||||
cur_frm.roles_editor = new wn.RoleEditor(role_area);
|
||||
} else {
|
||||
// called when creating a new profile
|
||||
// and need to clear previous profile's roles
|
||||
cur_frm.roles_editor.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -21,7 +27,8 @@ cur_frm.cscript.refresh = function(doc) {
|
|||
}
|
||||
cur_frm.cscript.enabled(doc);
|
||||
|
||||
cur_frm.roles_editor && cur_frm.roles_editor.show(doc.name);
|
||||
cur_frm.roles_editor && cur_frm.roles_editor.show();
|
||||
|
||||
if(user==doc.name) {
|
||||
// update display settings
|
||||
wn.ui.set_theme(doc.theme);
|
||||
|
|
@ -53,9 +60,7 @@ cur_frm.cscript.enabled = function(doc) {
|
|||
|
||||
cur_frm.cscript.validate = function(doc) {
|
||||
if(cur_frm.roles_editor) {
|
||||
doc.__temp = JSON.stringify({
|
||||
roles:cur_frm.roles_editor.get_roles()
|
||||
});
|
||||
cur_frm.roles_editor.set_roles_in_table()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +74,12 @@ wn.RoleEditor = Class.extend({
|
|||
callback: function(r) {
|
||||
me.roles = r.message;
|
||||
me.show_roles();
|
||||
|
||||
// refresh call could've already happened
|
||||
// when all role checkboxes weren't created
|
||||
if(cur_frm.doc) {
|
||||
cur_frm.roles_editor.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
@ -90,38 +101,63 @@ wn.RoleEditor = Class.extend({
|
|||
return false;
|
||||
})
|
||||
},
|
||||
show: function(uid) {
|
||||
show: function() {
|
||||
var me = this;
|
||||
this.uid = uid;
|
||||
// set user roles
|
||||
wn.call({
|
||||
method:'core.doctype.profile.profile.get_user_roles',
|
||||
args: {uid:uid},
|
||||
callback: function(r, rt) {
|
||||
$(me.wrapper).find('input[type="checkbox"]').attr('checked', false);
|
||||
for(var i in r.message) {
|
||||
$(me.wrapper)
|
||||
.find('[data-user-role="'+r.message[i]
|
||||
+'"] input[type="checkbox"]').attr('checked',true);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// uncheck all roles
|
||||
$(this.wrapper).find('input[type="checkbox"]').removeAttr("checked");
|
||||
|
||||
// set user roles as checked
|
||||
$.each(wn.model.get("UserRole", {parent: cur_frm.doc.name,
|
||||
parentfield: "user_roles"}), function(i, user_role) {
|
||||
$(me.wrapper)
|
||||
.find('[data-user-role="'+user_role.role
|
||||
+'"] input[type="checkbox"]').attr('checked', 'checked');
|
||||
});
|
||||
},
|
||||
set_roles_in_table: function() {
|
||||
var opts = this.get_roles();
|
||||
var existing_roles_map = {};
|
||||
var existing_roles_list = [];
|
||||
|
||||
$.each(wn.model.get("UserRole", {parent: cur_frm.doc.name,
|
||||
parentfield: "user_roles"}), function(i, user_role) {
|
||||
existing_roles_map[user_role.role] = user_role.name;
|
||||
existing_roles_list.push(user_role.role);
|
||||
});
|
||||
|
||||
// remove unchecked roles
|
||||
$.each(opts.unchecked_roles, function(i, role) {
|
||||
if(existing_roles_list.indexOf(role)!=-1) {
|
||||
wn.model.clear_doc("UserRole", existing_roles_map[role]);
|
||||
}
|
||||
});
|
||||
|
||||
// add new roles that are checked
|
||||
$.each(opts.checked_roles, function(i, role) {
|
||||
if(existing_roles_list.indexOf(role)==-1) {
|
||||
var user_role = wn.model.add_child(cur_frm.doc, "UserRole", "user_roles");
|
||||
user_role.role = role;
|
||||
}
|
||||
});
|
||||
|
||||
refresh_field("user_roles");
|
||||
},
|
||||
get_roles: function() {
|
||||
var set_roles = [];
|
||||
var unset_roles = [];
|
||||
var checked_roles = [];
|
||||
var unchecked_roles = [];
|
||||
$(this.wrapper).find('[data-user-role]').each(function() {
|
||||
var $check = $(this).find('input[type="checkbox"]');
|
||||
if($check.attr('checked')) {
|
||||
set_roles.push($(this).attr('data-user-role'));
|
||||
checked_roles.push($(this).attr('data-user-role'));
|
||||
} else {
|
||||
unset_roles.push($(this).attr('data-user-role'));
|
||||
unchecked_roles.push($(this).attr('data-user-role'));
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
set_roles: set_roles,
|
||||
unset_roles: unset_roles
|
||||
checked_roles: checked_roles,
|
||||
unchecked_roles: unchecked_roles
|
||||
}
|
||||
},
|
||||
show_permissions: function(role) {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class DocType:
|
|||
del self.doc.fields['__temp']
|
||||
|
||||
self.validate_max_users()
|
||||
self.update_roles()
|
||||
self.check_one_system_manager()
|
||||
|
||||
# do not allow disabling administrator/guest
|
||||
if not cint(self.doc.enabled) and self.doc.name in ["Administrator", "Guest"]:
|
||||
|
|
@ -88,44 +88,25 @@ class DocType:
|
|||
1. <b>Upgrade to the unlimited users plan</b>, or<br /> \
|
||||
2. <b>Disable one or more of your existing users and try again</b>""" \
|
||||
% {'active_users': active_users}, raise_exception=1)
|
||||
|
||||
def update_roles(self):
|
||||
"""update roles if set"""
|
||||
|
||||
if self.temp.get('roles'):
|
||||
from webnotes.model.doc import Document
|
||||
|
||||
# remove roles
|
||||
webnotes.conn.sql("""delete from tabUserRole where parent='%s'
|
||||
and role in ('%s')""" % (self.doc.name,
|
||||
"','".join(self.temp['roles']['unset_roles'])))
|
||||
|
||||
if "System Manager" in self.temp['roles']['unset_roles']:
|
||||
self.check_one_system_manager()
|
||||
|
||||
# add roles
|
||||
user_roles = webnotes.get_roles(self.doc.name)
|
||||
for role in self.temp['roles']['set_roles']:
|
||||
if not role in user_roles:
|
||||
self.add_role(role)
|
||||
|
||||
def add_role(self, role):
|
||||
d = webnotes.doc('UserRole')
|
||||
d.role = role
|
||||
d.parenttype = 'Profile'
|
||||
d.parentfield = 'user_roles'
|
||||
d.parent = self.doc.name
|
||||
d.save()
|
||||
|
||||
|
||||
def check_one_system_manager(self):
|
||||
if not webnotes.conn.sql("""select parent from tabUserRole where role='System Manager' and docstatus<2 and parent!='Administrator'"""):
|
||||
if webnotes.conn.sql("""select count(*) from `tabProfile`
|
||||
where name not in ('Administrator', 'Guest')""")[0][0] == 0:
|
||||
self.temp["roles"]["set_roles"].append("System Manager")
|
||||
return
|
||||
|
||||
webnotes.msgprint("""Cannot un-select as System Manager as there must
|
||||
be atleast one 'System Manager'.""", raise_exception=1)
|
||||
# if adding system manager, do nothing
|
||||
if not cint(self.doc.enabled) or ("System Manager" in [user_role.role for user_role in
|
||||
self.doclist.get({"parentfield": "user_roles"})]):
|
||||
return
|
||||
|
||||
if not webnotes.conn.sql("""select distinct parent from tabUserRole user_role
|
||||
where role='System Manager' and docstatus<2
|
||||
and parent not in ('Administrator', %s) and exists
|
||||
(select * from `tabProfile` profile
|
||||
where profile.name=user_role.parent and enabled=1)""", (self.doc.name,)):
|
||||
webnotes.msgprint("""Adding System Manager Role as there must
|
||||
be atleast one 'System Manager'.""")
|
||||
self.doclist.append({
|
||||
"doctype": "UserRole",
|
||||
"parentfield": "user_roles",
|
||||
"role": "System Manager"
|
||||
})
|
||||
|
||||
def on_update(self):
|
||||
# owner is always name
|
||||
|
|
@ -277,4 +258,4 @@ def get_perm_info(arg=None):
|
|||
def get_defaults(arg=None):
|
||||
return webnotes.conn.sql("""select defkey, defvalue from tabDefaultValue where
|
||||
parent=%s and parenttype = 'Profile'""", webnotes.form_dict['profile'])
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
[
|
||||
{
|
||||
"creation": "2013-02-06 16:11:18",
|
||||
"creation": "2013-02-11 12:30:10",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-02-11 11:43:26",
|
||||
"modified": "2013-02-13 09:35:48",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
|
|
@ -168,6 +168,7 @@
|
|||
"fieldtype": "Password",
|
||||
"hidden": 0,
|
||||
"label": "New Password",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -377,6 +378,26 @@
|
|||
"oldfieldname": "file_list",
|
||||
"oldfieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "roles_assigned_to_user",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 1,
|
||||
"label": "Roles Assigned To User",
|
||||
"no_copy": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "user_roles",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Roles Assigned",
|
||||
"options": "UserRole",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,14 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cint
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
self.doc, self.doclist = d, dl
|
||||
|
||||
def validate(self):
|
||||
if cint(self.doc.fields.get("__islocal")) and webnotes.conn.exists("UserRole", {
|
||||
"parent": self.doc.parent, "role": self.doc.role}):
|
||||
webnotes.msgprint("Role Already Exists", raise_exception=True)
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
[
|
||||
{
|
||||
"creation": "2013-01-10 16:34:04",
|
||||
"creation": "2013-02-06 11:30:13",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-02-06 11:43:05",
|
||||
"modified": "2013-02-13 07:51:57",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
"allow_print": 0,
|
||||
"autoname": "UR.#####",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"issingle": 0,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@
|
|||
|
||||
"lib/public/js/lib/tiny_mce_3.5.7/jquery.tinymce.js:concat",
|
||||
"lib/public/js/lib/mousetrap.min.js",
|
||||
"lib/public/js/lib/number_formatter.js",
|
||||
|
||||
"lib/public/js/wn/provide.js",
|
||||
"lib/public/js/wn/class.js",
|
||||
|
|
@ -100,6 +99,7 @@
|
|||
"lib/public/js/wn/misc/tools.js",
|
||||
"lib/public/js/wn/misc/about.js",
|
||||
"lib/public/js/wn/misc/datetime.js",
|
||||
"lib/public/js/wn/misc/number_format.js",
|
||||
|
||||
"lib/public/js/legacy/utils/handler.js",
|
||||
"lib/public/js/legacy/utils/printElement.js",
|
||||
|
|
@ -123,6 +123,7 @@
|
|||
"lib/public/js/wn/views/reportview.js",
|
||||
"lib/public/js/wn/views/grid_report.js",
|
||||
"lib/public/js/wn/views/communication.js",
|
||||
"lib/public/js/wn/views/test_runner.js",
|
||||
"lib/public/js/wn/form/formatters.js",
|
||||
|
||||
"lib/public/js/legacy/webpage/page_header.js",
|
||||
|
|
|
|||
|
|
@ -28,47 +28,6 @@ function fmt_money(v, format){
|
|||
return format_number(v, format);
|
||||
}
|
||||
|
||||
function format_currency(v, currency) {
|
||||
var format = wn.model.get_value("Currency", currency,
|
||||
"number_format") || get_number_format();
|
||||
|
||||
var symbol = get_currency_symbol(currency);
|
||||
|
||||
if(symbol)
|
||||
return symbol + " " + format_number(v, format);
|
||||
else
|
||||
return format_number(v, format);
|
||||
}
|
||||
|
||||
function get_currency_symbol(currency) {
|
||||
if(wn.boot.sysdefaults.hide_currency_symbol=="Yes")
|
||||
return null;
|
||||
|
||||
if(!currency)
|
||||
currency = wn.boot.sysdefaults.currency;
|
||||
|
||||
return wn.model.get_value("Currency", currency, "symbol") || currency;
|
||||
}
|
||||
|
||||
var global_number_format = null;
|
||||
function get_number_format() {
|
||||
if(!global_number_format) {
|
||||
global_number_format = wn.boot.sysdefaults.number_format
|
||||
|| wn.model.get_value("Currency", wn.boot.sysdefaults.currency, "number_format")
|
||||
|| "#,###.##";
|
||||
}
|
||||
return global_number_format;
|
||||
}
|
||||
|
||||
var number_format_info = {
|
||||
"#,###.##": {decimal_str:".", group_sep:",", precision:2},
|
||||
"#.###,##": {decimal_str:",", group_sep:".", precision:2},
|
||||
"# ###.##": {decimal_str:".", group_sep:" ", precision:2},
|
||||
"#,###.###": {decimal_str:".", group_sep:",", precision:3},
|
||||
"#,##,###.##": {decimal_str:".", group_sep:",", precision:2},
|
||||
"#.###": {decimal_str:"", group_sep:".", precision:0},
|
||||
"#,###": {decimal_str:"", group_sep:",", precision:0},
|
||||
}
|
||||
|
||||
// to title case
|
||||
function toTitle(str){
|
||||
|
|
@ -150,7 +109,7 @@ function flt(v, decimals) {
|
|||
}
|
||||
|
||||
// strip groups (,)
|
||||
if(number_format_info.group_sep==".") {
|
||||
if(wn.number_format_info.group_sep==".") {
|
||||
v = v.replace(/\./g,'');
|
||||
|
||||
// sanitize decimal separator to .
|
||||
|
|
|
|||
|
|
@ -898,6 +898,9 @@ _f.Frm.prototype.save = function(save_action, callback, btn, on_error) {
|
|||
$(document.activeElement).blur();
|
||||
var me = this;
|
||||
|
||||
if((!this.meta.in_dialog || this.in_form) && !this.meta.istable)
|
||||
scroll(0, 0);
|
||||
|
||||
// validate
|
||||
if(save_action!="Cancel") {
|
||||
validated = true;
|
||||
|
|
|
|||
244
public/js/lib/jquery/qunit.css
Normal file
244
public/js/lib/jquery/qunit.css
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/**
|
||||
* QUnit v1.11.0 - A JavaScript Unit Testing Framework
|
||||
*
|
||||
* http://qunitjs.com
|
||||
*
|
||||
* Copyright 2012 jQuery Foundation and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*/
|
||||
|
||||
/** Font Family and Sizes */
|
||||
|
||||
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
|
||||
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
|
||||
#qunit-tests { font-size: smaller; }
|
||||
|
||||
|
||||
/** Resets */
|
||||
|
||||
#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/** Header */
|
||||
|
||||
#qunit-header {
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
|
||||
color: #8699a4;
|
||||
background-color: #0d3349;
|
||||
|
||||
font-size: 1.5em;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
|
||||
border-radius: 5px 5px 0 0;
|
||||
-moz-border-radius: 5px 5px 0 0;
|
||||
-webkit-border-top-right-radius: 5px;
|
||||
-webkit-border-top-left-radius: 5px;
|
||||
}
|
||||
|
||||
#qunit-header a {
|
||||
text-decoration: none;
|
||||
color: #c2ccd1;
|
||||
}
|
||||
|
||||
#qunit-header a:hover,
|
||||
#qunit-header a:focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar label {
|
||||
display: inline-block;
|
||||
padding: 0 .5em 0 .1em;
|
||||
}
|
||||
|
||||
#qunit-banner {
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar {
|
||||
padding: 0.5em 0 0.5em 2em;
|
||||
color: #5E740B;
|
||||
background-color: #eee;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#qunit-userAgent {
|
||||
padding: 0.5em 0 0.5em 2.5em;
|
||||
background-color: #2b81af;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
|
||||
}
|
||||
|
||||
#qunit-modulefilter-container {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/** Tests: Pass/Fail */
|
||||
|
||||
#qunit-tests {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests li {
|
||||
padding: 0.4em 0.5em 0.4em 2.5em;
|
||||
border-bottom: 1px solid #fff;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#qunit-tests li strong {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#qunit-tests li a {
|
||||
padding: 0.5em;
|
||||
color: #c2ccd1;
|
||||
text-decoration: none;
|
||||
}
|
||||
#qunit-tests li a:hover,
|
||||
#qunit-tests li a:focus {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#qunit-tests li .runtime {
|
||||
float: right;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.qunit-assert-list {
|
||||
margin-top: 0.5em;
|
||||
padding: 0.5em;
|
||||
|
||||
background-color: #fff;
|
||||
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
.qunit-collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#qunit-tests table {
|
||||
border-collapse: collapse;
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
#qunit-tests th {
|
||||
text-align: right;
|
||||
vertical-align: top;
|
||||
padding: 0 .5em 0 0;
|
||||
}
|
||||
|
||||
#qunit-tests td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#qunit-tests pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#qunit-tests del {
|
||||
background-color: #e0f2be;
|
||||
color: #374e0c;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#qunit-tests ins {
|
||||
background-color: #ffcaca;
|
||||
color: #500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*** Test Counts */
|
||||
|
||||
#qunit-tests b.counts { color: black; }
|
||||
#qunit-tests b.passed { color: #5E740B; }
|
||||
#qunit-tests b.failed { color: #710909; }
|
||||
|
||||
#qunit-tests li li {
|
||||
padding: 5px;
|
||||
background-color: #fff;
|
||||
border-bottom: none;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
/*** Passing Styles */
|
||||
|
||||
#qunit-tests li li.pass {
|
||||
color: #3c510c;
|
||||
background-color: #fff;
|
||||
border-left: 10px solid #C6E746;
|
||||
}
|
||||
|
||||
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
|
||||
#qunit-tests .pass .test-name { color: #366097; }
|
||||
|
||||
#qunit-tests .pass .test-actual,
|
||||
#qunit-tests .pass .test-expected { color: #999999; }
|
||||
|
||||
#qunit-banner.qunit-pass { background-color: #C6E746; }
|
||||
|
||||
/*** Failing Styles */
|
||||
|
||||
#qunit-tests li li.fail {
|
||||
color: #710909;
|
||||
background-color: #fff;
|
||||
border-left: 10px solid #EE5757;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#qunit-tests > li:last-child {
|
||||
border-radius: 0 0 5px 5px;
|
||||
-moz-border-radius: 0 0 5px 5px;
|
||||
-webkit-border-bottom-right-radius: 5px;
|
||||
-webkit-border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
|
||||
#qunit-tests .fail .test-name,
|
||||
#qunit-tests .fail .module-name { color: #000000; }
|
||||
|
||||
#qunit-tests .fail .test-actual { color: #EE5757; }
|
||||
#qunit-tests .fail .test-expected { color: green; }
|
||||
|
||||
#qunit-banner.qunit-fail { background-color: #EE5757; }
|
||||
|
||||
|
||||
/** Result */
|
||||
|
||||
#qunit-testresult {
|
||||
padding: 0.5em 0.5em 0.5em 2.5em;
|
||||
|
||||
color: #2b81af;
|
||||
background-color: #D2E0E6;
|
||||
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
#qunit-testresult .module-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/** Fixture */
|
||||
|
||||
#qunit-fixture {
|
||||
position: absolute;
|
||||
top: -10000px;
|
||||
left: -10000px;
|
||||
width: 1000px;
|
||||
height: 1000px;
|
||||
}
|
||||
2152
public/js/lib/jquery/qunit.js
vendored
Normal file
2152
public/js/lib/jquery/qunit.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,84 +0,0 @@
|
|||
/**
|
||||
* Adapted from:
|
||||
* -------------
|
||||
* @preserve IntegraXor Web SCADA - JavaScript Number Formatter
|
||||
* http://www.integraxor.com/
|
||||
* author: KPL, KHL
|
||||
* (c)2011 ecava
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// param: Mask & Value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
window['format_number'] = function(v, m, decimals){
|
||||
if (!m) {
|
||||
m = get_number_format();
|
||||
}
|
||||
var info = number_format_info[m];
|
||||
if(!info) {
|
||||
info = {decimal_str:".", group_sep:",", precision:2};
|
||||
}
|
||||
|
||||
if(isNaN(+v)) {
|
||||
v=0;
|
||||
};
|
||||
|
||||
//convert any string to number according to formation sign.
|
||||
var format = m;
|
||||
var v = m.charAt(0) == '-'? -v: +v;
|
||||
var isNegative = v<0? v= -v: 0; //process only abs(), and turn on flag.
|
||||
|
||||
//Fix the decimal first, toFixed will auto fill trailing zero.
|
||||
decimals = decimals || info.precision;
|
||||
v = v.toFixed(decimals);
|
||||
|
||||
var part = v.split('.');
|
||||
|
||||
m = m.split(info.decimal_str);
|
||||
var szSep = m[0].split( info.group_sep); //look for separator
|
||||
m[0] = szSep.join(''); //join back without separator for counting the pos of any leading 0.
|
||||
|
||||
var pos_lead_zero = m[0] && m[0].indexOf('0');
|
||||
if (pos_lead_zero > -1 ) {
|
||||
while (part[0].length < (m[0].length - pos_lead_zero)) {
|
||||
part[0] = '0' + part[0];
|
||||
}
|
||||
}
|
||||
else if (+part[0] == 0){
|
||||
part[0] = '';
|
||||
}
|
||||
|
||||
v = v.split('.');
|
||||
v[0] = part[0];
|
||||
|
||||
//process the first group separator from decimal (.) only, the rest ignore.
|
||||
//get the length of the last slice of split result.
|
||||
var pos_separator = ( szSep[1] && szSep[ szSep.length-1].length);
|
||||
if (pos_separator) {
|
||||
var integer = v[0];
|
||||
var str = '';
|
||||
var offset = integer.length % pos_separator;
|
||||
for (var i=integer.length; i>=0; i--) {
|
||||
var l = replace_all(str, info.group_sep, "").length;
|
||||
if(format=="#,##,###.##" && str.indexOf(",")!=-1) { // INR
|
||||
pos_separator = 2;
|
||||
l += 1;
|
||||
}
|
||||
|
||||
str += integer.charAt(i); //ie6 only support charAt for sz.
|
||||
//-pos_separator so that won't trail separator on full length
|
||||
if (l && !((l+1) % pos_separator) && i!=0 ) {
|
||||
str += info.group_sep;
|
||||
}
|
||||
}
|
||||
v[0] = str.split("").reverse().join("");
|
||||
}
|
||||
if(v[0]+""=="") {
|
||||
v[0]="0";
|
||||
}
|
||||
|
||||
v[1] = (m[1] && v[1])? info.decimal_str+v[1] : "";
|
||||
return (isNegative?'-':'') + v[0] + v[1]; //put back any negation and combine integer and fraction.
|
||||
};
|
||||
|
|
@ -107,8 +107,6 @@ wn.Application = Class.extend({
|
|||
wn.temp_container = $("<div id='#temp-container' style='display: none;'>")
|
||||
.appendTo("body");
|
||||
wn.container = new wn.views.Container();
|
||||
wn.views.make_403();
|
||||
wn.views.make_404();
|
||||
}
|
||||
},
|
||||
make_nav_bar: function() {
|
||||
|
|
|
|||
105
public/js/wn/misc/number_format.js
Normal file
105
public/js/wn/misc/number_format.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2013 Web Notes Technologies Pvt Ltd
|
||||
// MIT Licensed. See license.txt
|
||||
|
||||
wn.number_format_info = {
|
||||
"#,###.##": {decimal_str:".", group_sep:",", precision:2},
|
||||
"#.###,##": {decimal_str:",", group_sep:".", precision:2},
|
||||
"# ###.##": {decimal_str:".", group_sep:" ", precision:2},
|
||||
"#,###.###": {decimal_str:".", group_sep:",", precision:3},
|
||||
"#,##,###.##": {decimal_str:".", group_sep:",", precision:2},
|
||||
"#.###": {decimal_str:"", group_sep:".", precision:0},
|
||||
"#,###": {decimal_str:"", group_sep:",", precision:0},
|
||||
}
|
||||
|
||||
window.format_number = function(v, format, decimals){
|
||||
if (!format) {
|
||||
format = get_number_format();
|
||||
}
|
||||
var info = wn.number_format_info[format];
|
||||
if(!info) {
|
||||
info = {decimal_str:".", group_sep:",", precision:2};
|
||||
}
|
||||
|
||||
if(isNaN(+v)) {
|
||||
v=0;
|
||||
};
|
||||
|
||||
// remove group separators (if any)
|
||||
if(typeof v=="string") {
|
||||
v = replace_all(info.group_sep, "");
|
||||
}
|
||||
|
||||
if(v<0) var is_negative = true;
|
||||
v = Math.abs(v);
|
||||
|
||||
//Fix the decimal first, toFixed will auto fill trailing zero.
|
||||
decimals = decimals || info.precision;
|
||||
|
||||
v = v.toFixed(decimals);
|
||||
|
||||
var part = v.split('.');
|
||||
|
||||
// get group position and parts
|
||||
var group_position = info.group_sep ? 3 : 0;
|
||||
|
||||
if (group_position) {
|
||||
var integer = part[0];
|
||||
var str = '';
|
||||
var offset = integer.length % group_position;
|
||||
for (var i=integer.length; i>=0; i--) {
|
||||
var l = replace_all(str, info.group_sep, "").length;
|
||||
if(format=="#,##,###.##" && str.indexOf(",")!=-1) { // INR
|
||||
group_position = 2;
|
||||
l += 1;
|
||||
}
|
||||
|
||||
str += integer.charAt(i);
|
||||
|
||||
if (l && !((l+1) % group_position) && i!=0 ) {
|
||||
str += info.group_sep;
|
||||
}
|
||||
}
|
||||
part[0] = str.split("").reverse().join("");
|
||||
}
|
||||
if(part[0]+""=="") {
|
||||
part[0]="0";
|
||||
}
|
||||
|
||||
// join decimal
|
||||
part[1] = part[1] ? (info.decimal_str + part[1]) : "";
|
||||
|
||||
// join
|
||||
return (is_negative ? "-" : "") + part[0] + part[1];
|
||||
};
|
||||
|
||||
function format_currency(v, currency) {
|
||||
var format = wn.model.get_value("Currency", currency,
|
||||
"number_format") || get_number_format();
|
||||
|
||||
var symbol = get_currency_symbol(currency);
|
||||
|
||||
if(symbol)
|
||||
return symbol + " " + format_number(v, format);
|
||||
else
|
||||
return format_number(v, format);
|
||||
}
|
||||
|
||||
function get_currency_symbol(currency) {
|
||||
if(wn.boot.sysdefaults.hide_currency_symbol=="Yes")
|
||||
return null;
|
||||
|
||||
if(!currency)
|
||||
currency = wn.boot.sysdefaults.currency;
|
||||
|
||||
return wn.model.get_value("Currency", currency, "symbol") || currency;
|
||||
}
|
||||
|
||||
var global_number_format = null;
|
||||
function get_number_format() {
|
||||
if(!global_number_format) {
|
||||
global_number_format = wn.boot.sysdefaults.number_format
|
||||
|| wn.model.get_value("Currency", wn.boot.sysdefaults.currency, "number_format")
|
||||
|| "#,###.##";
|
||||
}
|
||||
return global_number_format;
|
||||
}
|
||||
35
public/js/wn/misc/tests/test_number_format.js
Normal file
35
public/js/wn/misc/tests/test_number_format.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
module("Number Formatting");
|
||||
|
||||
test("#,###.##", function() {
|
||||
equal(format_number(100, "#,###.##"), "100.00");
|
||||
equal(format_number(1000, "#,###.##"), "1,000.00");
|
||||
equal(format_number(10000, "#,###.##"), "10,000.00");
|
||||
equal(format_number(1000000, "#,###.##"), "1,000,000.00");
|
||||
equal(format_number(1000000.345, "#,###.##"), "1,000,000.34");
|
||||
});
|
||||
|
||||
test("#,##,###.##", function() {
|
||||
equal(format_number(100, "#,##,###.##"), "100.00");
|
||||
equal(format_number(1000, "#,##,###.##"), "1,000.00");
|
||||
equal(format_number(10000, "#,##,###.##"), "10,000.00");
|
||||
equal(format_number(1000000, "#,##,###.##"), "10,00,000.00");
|
||||
equal(format_number(1000000.341, "#,##,###.##"), "10,00,000.34");
|
||||
equal(format_number(10000000.341, "#,##,###.##"), "1,00,00,000.34");
|
||||
});
|
||||
|
||||
test("#.###,##", function() {
|
||||
equal(format_number(100, "#.###,##"), "100,00");
|
||||
equal(format_number(1000, "#.###,##"), "1.000,00");
|
||||
equal(format_number(10000, "#.###,##"), "10.000,00");
|
||||
equal(format_number(1000000, "#.###,##"), "1.000.000,00");
|
||||
equal(format_number(1000000.345, "#.###,##"), "1.000.000,34");
|
||||
});
|
||||
|
||||
test("#.###", function() {
|
||||
equal(format_number(100, "#.###"), "100");
|
||||
equal(format_number(1000, "#.###"), "1.000");
|
||||
equal(format_number(10000, "#.###"), "10.000");
|
||||
equal(format_number(-100000, "#.###"), "-100.000");
|
||||
equal(format_number(1000000, "#.###"), "1.000.000");
|
||||
equal(format_number(1000000.345, "#.###"), "1.000.000");
|
||||
});
|
||||
|
|
@ -15,6 +15,7 @@ wn.views.Container = Class.extend({
|
|||
add_page: function(label, onshow, onhide) {
|
||||
var page = $('<div class="content"></div>')
|
||||
.attr('id', "page-" + label)
|
||||
.toggle(false)
|
||||
.appendTo(this.container).get(0);
|
||||
if(onshow)
|
||||
$(page).bind('show', onshow);
|
||||
|
|
|
|||
|
|
@ -8,13 +8,17 @@ wn.views.formview = {
|
|||
// renamed (on save)?
|
||||
if(wn.model.new_names[dn])
|
||||
dn = wn.model.new_names[dn];
|
||||
|
||||
wn.views.formview.make(dt, dn, true);
|
||||
},
|
||||
make: function(dt, dn, show) {
|
||||
// show doctype
|
||||
wn.model.with_doctype(dt, function() {
|
||||
wn.model.with_doc(dt, dn, function(dn, r) {
|
||||
if(r && r['403']) return; // not permitted
|
||||
|
||||
if(!(locals[dt] && locals[dt][dn])) {
|
||||
// doc not found, but starts with New,
|
||||
// make a new doc and set it
|
||||
if(dn && dn.substr(0,4)=="New ") {
|
||||
var new_name = wn.model.make_new_doc_and_get_name(dt);
|
||||
wn.views.formview.show(dt, new_name);
|
||||
|
|
@ -28,10 +32,13 @@ wn.views.formview = {
|
|||
wn.views.formview[dt] = wn.container.add_page('Form - ' + dt);
|
||||
wn.views.formview[dt].frm = new _f.Frm(dt, wn.views.formview[dt], true);
|
||||
}
|
||||
wn.container.change_to('Form - ' + dt);
|
||||
wn.views.formview[dt].frm.refresh(dn);
|
||||
|
||||
if(show) {
|
||||
wn.container.change_to('Form - ' + dt);
|
||||
wn.views.formview[dt].frm.refresh(dn);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
},
|
||||
create: function(dt) {
|
||||
var new_name = wn.model.make_new_doc_and_get_name(dt);
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ wn.views.GridReport = Class.extend({
|
|||
currency_formatter: function(row, cell, value, columnDef, dataContext) {
|
||||
return repl('<div style="text-align: right; %(_style)s">%(value)s</div>', {
|
||||
_style: dataContext._style || "",
|
||||
value: dataContext._no_format ? value : format_number(value)
|
||||
value: format_number(value)
|
||||
});
|
||||
},
|
||||
text_formatter: function(row, cell, value, columnDef, dataContext) {
|
||||
|
|
|
|||
|
|
@ -32,27 +32,29 @@ wn.views.ListView = Class.extend({
|
|||
this.fields = [t + 'name', t + 'owner', t + 'docstatus',
|
||||
t + '_user_tags', t + 'modified', t + 'modified_by'];
|
||||
this.stats = ['_user_tags'];
|
||||
|
||||
|
||||
|
||||
$.each(wn.model.get("DocField", {"parent":this.doctype, "in_list_view":1}), function(i,d) {
|
||||
if(d.fieldtype=="Image" && d.options) {
|
||||
me.fields.push(t + "`" + d.options + "`");
|
||||
} else {
|
||||
me.fields.push(t + "`" + d.fieldname + "`");
|
||||
}
|
||||
|
||||
if(d.fieldtype=="Select") {
|
||||
me.stats.push(d.fieldname);
|
||||
}
|
||||
|
||||
// currency field for symbol (multi-currency)
|
||||
if(d.fieldtype=="Currency" && d.options) {
|
||||
if(d.options.indexOf(":")!=-1) {
|
||||
me.fields.push(t + "`" + d.options.split(":")[1] + "`");
|
||||
} else {
|
||||
if(wn.perm.has_perm(me.doctype, d.permlevel, READ)) {
|
||||
if(d.fieldtype=="Image" && d.options) {
|
||||
me.fields.push(t + "`" + d.options + "`");
|
||||
};
|
||||
}
|
||||
} else {
|
||||
me.fields.push(t + "`" + d.fieldname + "`");
|
||||
}
|
||||
|
||||
if(d.fieldtype=="Select") {
|
||||
me.stats.push(d.fieldname);
|
||||
}
|
||||
|
||||
// currency field for symbol (multi-currency)
|
||||
if(d.fieldtype=="Currency" && d.options) {
|
||||
if(d.options.indexOf(":")!=-1) {
|
||||
me.fields.push(t + "`" + d.options.split(":")[1] + "`");
|
||||
} else {
|
||||
me.fields.push(t + "`" + d.options + "`");
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// additional fields
|
||||
|
|
|
|||
|
|
@ -2,13 +2,18 @@
|
|||
// License: MIT. See license.txt
|
||||
|
||||
wn.provide('wn.views.pageview');
|
||||
wn.provide("wn.standard_pages");
|
||||
|
||||
wn.views.pageview = {
|
||||
with_page: function(name, callback) {
|
||||
if(name=="403" || name=="404") {
|
||||
if(in_list(keys(wn.standard_pages), name)) {
|
||||
if(!wn.pages[name]) {
|
||||
wn.standard_pages[name]();
|
||||
}
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if((locals.Page && locals.Page[name]) || name==window.page_name) {
|
||||
callback();
|
||||
} else {
|
||||
|
|
@ -79,20 +84,20 @@ wn.views.Page = Class.extend({
|
|||
})
|
||||
|
||||
|
||||
wn.views.make_404 = function() {
|
||||
wn.standard_pages["404"] = function() {
|
||||
var page = wn.container.add_page('404');
|
||||
$(page).html('<div class="layout-wrapper">\
|
||||
<h3><i class="icon-exclamation-sign"></i> '+wn._('Not Found')+'</h3><br>\
|
||||
<p>'+wn._('Sorry we were unable to find what you were looking for.')+'</p>\
|
||||
<p><a href="#">'+wn._('Go back to home')+'</a></p>\
|
||||
</div>').toggle(false);
|
||||
</div>');
|
||||
};
|
||||
|
||||
wn.views.make_403 = function() {
|
||||
wn.standard_pages["403"] = function() {
|
||||
var page = wn.container.add_page('403');
|
||||
$(page).html('<div class="layout-wrapper">\
|
||||
<h3><i class="icon-minus-sign"></i> '+wn._('Not Permitted')+'</h3><br>\
|
||||
<p>'+wn._('Sorry you are not permitted to view this page.')+'.</p>\
|
||||
<p><a href="#">'+wn._('Go back to home')+'</a></p>\
|
||||
</div>').toggle(false);
|
||||
</div>');
|
||||
};
|
||||
28
public/js/wn/views/test_runner.js
Normal file
28
public/js/wn/views/test_runner.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2013 Web Notes Technologies Pvt Ltd
|
||||
// MIT Licensed. See license.txt
|
||||
|
||||
wn.standard_pages["test-runner"] = function() {
|
||||
var wrapper = wn.container.add_page('test-runner');
|
||||
|
||||
wn.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
single_column: true,
|
||||
title: wn._("Test Runner")
|
||||
});
|
||||
|
||||
$("<div id='qunit'></div>").appendTo($(wrapper).find(".layout-main"));
|
||||
|
||||
var route = wn.get_route();
|
||||
if(route.length < 2) {
|
||||
msgprint("To run a test add the module name in the route after 'test-runner/'. \
|
||||
For example, #test-runner/lib/js/wn/test_app.js");
|
||||
return;
|
||||
}
|
||||
|
||||
wn.require("lib/js/lib/jquery/qunit.js");
|
||||
wn.require("lib/js/lib/jquery/qunit.css");
|
||||
|
||||
QUnit.load();
|
||||
|
||||
wn.require(route.splice(1).join("/"));
|
||||
}
|
||||
|
|
@ -255,10 +255,10 @@ class Database:
|
|||
"""Get a single / multiple value from a record.
|
||||
For Single DocType, let filters be = None"""
|
||||
|
||||
if fieldname!="*" and isinstance(fieldname, basestring):
|
||||
fieldname = "`" + fieldname + "`"
|
||||
|
||||
if filters is not None and (filters!=doctype or filters=='DocType'):
|
||||
if fieldname!="*" and isinstance(fieldname, basestring):
|
||||
fieldname = "`" + fieldname + "`"
|
||||
|
||||
fl = isinstance(fieldname, basestring) and fieldname or \
|
||||
("`" + "`, `".join(fieldname) + "`")
|
||||
conditions, filters = self.build_conditions(filters)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue