From e45ef41f2e403db83f1dccd7c7d3ac59742327ef Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 2 Aug 2011 15:53:27 +0530 Subject: [PATCH 01/27] defs fix in doctype --- cgi-bin/core/doctype/doctype/doctype.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi-bin/core/doctype/doctype/doctype.py b/cgi-bin/core/doctype/doctype/doctype.py index de8e2e1d4c..b96ec932f1 100644 --- a/cgi-bin/core/doctype/doctype/doctype.py +++ b/cgi-bin/core/doctype/doctype/doctype.py @@ -80,7 +80,7 @@ class DocType: self.change_modified_of_parent() - import webnotes.defs + from webnotes import defs from webnotes.utils.transfer import in_transfer if (not in_transfer) and getattr(defs,'developer_mode', 0): From 71761d009a71468e548512198c2d16ba46aa0f74 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 5 Aug 2011 13:02:13 +0530 Subject: [PATCH 02/27] fix to scheduler.py --- cgi-bin/webnotes/utils/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi-bin/webnotes/utils/scheduler.py b/cgi-bin/webnotes/utils/scheduler.py index 69f9c488e5..8290399ac4 100644 --- a/cgi-bin/webnotes/utils/scheduler.py +++ b/cgi-bin/webnotes/utils/scheduler.py @@ -138,7 +138,7 @@ class Scheduler: # if recurring, update next_execution if e['recurring']: - self.conn.sql("update Event set next_execution = addtime(now(), sec_to_time(%s))", e['interval']) + self.conn.sql("update Event set next_execution = addtime(now(), sec_to_time(%s)) where event=%s", (e['interval'], e['event']) # else clear else: From b113599ed2d3a976160e5eecc74cf37dac782601 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 5 Aug 2011 13:04:00 +0530 Subject: [PATCH 03/27] fix to scheduler.py --- cgi-bin/webnotes/utils/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi-bin/webnotes/utils/scheduler.py b/cgi-bin/webnotes/utils/scheduler.py index 8290399ac4..96db7bb5d8 100644 --- a/cgi-bin/webnotes/utils/scheduler.py +++ b/cgi-bin/webnotes/utils/scheduler.py @@ -138,7 +138,7 @@ class Scheduler: # if recurring, update next_execution if e['recurring']: - self.conn.sql("update Event set next_execution = addtime(now(), sec_to_time(%s)) where event=%s", (e['interval'], e['event']) + self.conn.sql("update Event set next_execution = addtime(now(), sec_to_time(%s)) where event=%s", (e['interval'], e['event'])) # else clear else: From 7627a051da62e2113ef2ef19e6f368986eb99833 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 5 Aug 2011 17:43:53 +0530 Subject: [PATCH 04/27] restore db fix. Allow dbname with $. Terminal didn't allow $ without escape char. --- cgi-bin/webnotes/model/db_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi-bin/webnotes/model/db_schema.py b/cgi-bin/webnotes/model/db_schema.py index 0ab2de0b78..e1e02058d2 100644 --- a/cgi-bin/webnotes/model/db_schema.py +++ b/cgi-bin/webnotes/model/db_schema.py @@ -358,7 +358,7 @@ class DbManager: mysql = mysql_path and os.path.join(mysql_path, 'mysql') or 'mysql' try: - ret = os.system("%s -u root -p%s %s < %s"%(mysql, root_password.replace(" ", "\ "), target, source)) + ret = os.system("%s -u root -p%s %s < %s"%(mysql, root_password.replace(" ", "\ "), target.replace("$", "\$"), source)) except Exception,e: raise e From d99d252a702e10618732e31f5a311529e466ec39 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 8 Aug 2011 16:28:10 +0530 Subject: [PATCH 05/27] Block unregistered users from resetting password --- cgi-bin/webnotes/profile.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index dd135ee1ba..57d938f2a4 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -149,11 +149,14 @@ class Profile: pwd = self.get_random_password() # get profile - profile = webnotes.conn.sql("SELECT name, email, first_name, last_name FROM tabProfile WHERE name=%s OR email=%s",(self.name, self.name)) + profile = webnotes.conn.sql("SELECT name, email, first_name, last_name, registered FROM tabProfile WHERE name=%s OR email=%s",(self.name, self.name)) if not profile: raise Exception, "Profile %s not found" % self.name - + elif not profile[0][4]: + # if an unregistered user tries to reset password + raise Exception, "You cannot reset your password as you have not completed registration. You need to complete registration using the link provided in the email." + # update tab Profile webnotes.conn.sql("UPDATE tabProfile SET password=password(%s) WHERE name=%s", (pwd, profile[0][0])) From ce61112bfd44f5ce74d446b4ae9a8b19349b1488 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 8 Aug 2011 16:52:09 +0530 Subject: [PATCH 06/27] Block a user from resetting password if registration is not complete --- cgi-bin/webnotes/profile.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index 57d938f2a4..bb9a201da2 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -149,13 +149,16 @@ class Profile: pwd = self.get_random_password() # get profile - profile = webnotes.conn.sql("SELECT name, email, first_name, last_name, registered FROM tabProfile WHERE name=%s OR email=%s",(self.name, self.name)) - + profile = webnotes.conn.sql("SELECT name, email, first_name, last_name FROM tabProfile WHERE name=%s OR email=%s",(self.name, self.name)) + + profile_cols = [desc[0] for desc in webnotes.conn.sql("DESCRIBE tabProfile")] + if not profile: raise Exception, "Profile %s not found" % self.name - elif not profile[0][4]: + elif 'registered' in profile_cols: + if not webnotes.conn.sql("SELECT registered FROM tabProfile WHERE name=%s", self.name)[0][0]: # if an unregistered user tries to reset password - raise Exception, "You cannot reset your password as you have not completed registration. You need to complete registration using the link provided in the email." + raise Exception, "You cannot reset your password as you have not completed registration. You need to complete registration using the link provided in the email." # update tab Profile webnotes.conn.sql("UPDATE tabProfile SET password=password(%s) WHERE name=%s", (pwd, profile[0][0])) From a7241e27dd05fd9ba413f34d4ebcb32df5400332 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 12:30:42 +0530 Subject: [PATCH 07/27] use cstr instead of str in msgprint --- cgi-bin/core/doctype/sandbox/sandbox.txt | 13 ++++++++++++- cgi-bin/webnotes/__init__.py | 6 ++++-- cgi-bin/webnotes/utils/__init__.py | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/cgi-bin/core/doctype/sandbox/sandbox.txt b/cgi-bin/core/doctype/sandbox/sandbox.txt index cae1065f59..c0dd5a3a94 100644 --- a/cgi-bin/core/doctype/sandbox/sandbox.txt +++ b/cgi-bin/core/doctype/sandbox/sandbox.txt @@ -76,7 +76,18 @@ 'fieldname': 'test_link', 'fieldtype': 'Link', 'idx': 2, - 'label': 'Test Link' + 'label': 'Test Link', + 'options': 'Profile' + }, + + # DocField + { + 'doctype': 'DocField', + 'fieldname': 'test_select', + 'fieldtype': 'Select', + 'idx': 2, + 'label': 'Test Select', + 'options': 'A\nB\nC' }, # DocField diff --git a/cgi-bin/webnotes/__init__.py b/cgi-bin/webnotes/__init__.py index 6b77d0c7d3..06833e2e77 100644 --- a/cgi-bin/webnotes/__init__.py +++ b/cgi-bin/webnotes/__init__.py @@ -57,6 +57,8 @@ cookies = {} auto_masters = {} tenant_id = None +from webnotes.utils import cstr + # # Custom Class (no traceback) # @@ -90,13 +92,13 @@ def errprint(msg): """ Append to the :data:`debug log` """ - debug_log.append(str(msg or '')) + debug_log.append(cstr(msg or '')) def msgprint(msg, small=0, raise_exception=0): """ Append to the :data:`message_log` """ - message_log.append((small and '__small:' or '')+str(msg or '')) + message_log.append((small and '__small:' or '')+cstr(msg or '')) if raise_exception: raise ValidationError diff --git a/cgi-bin/webnotes/utils/__init__.py b/cgi-bin/webnotes/utils/__init__.py index e770963a7c..5ee963863f 100644 --- a/cgi-bin/webnotes/utils/__init__.py +++ b/cgi-bin/webnotes/utils/__init__.py @@ -295,7 +295,7 @@ def cstr(s): s = s.encode('utf-8', 'ignore') except: pass - return str(s) + return unicode(s) def str_esc_quote(s): """ From aee16cdfdc5f8e34fba70e888a92ffd4d349507a Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 13:27:15 +0530 Subject: [PATCH 08/27] fix for unicode, ask to use utf-8 encoding --- cgi-bin/webnotes/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi-bin/webnotes/utils/__init__.py b/cgi-bin/webnotes/utils/__init__.py index 5ee963863f..1f3e661515 100644 --- a/cgi-bin/webnotes/utils/__init__.py +++ b/cgi-bin/webnotes/utils/__init__.py @@ -295,7 +295,7 @@ def cstr(s): s = s.encode('utf-8', 'ignore') except: pass - return unicode(s) + return unicode(s, 'utf-8') def str_esc_quote(s): """ From 1fc02c18870ad3b1944586594f6bdc113712b378 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 13:32:20 +0530 Subject: [PATCH 09/27] fix for unicode, ask to use utf-8 encoding --- cgi-bin/webnotes/utils/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cgi-bin/webnotes/utils/__init__.py b/cgi-bin/webnotes/utils/__init__.py index 1f3e661515..f8156046c2 100644 --- a/cgi-bin/webnotes/utils/__init__.py +++ b/cgi-bin/webnotes/utils/__init__.py @@ -295,7 +295,10 @@ def cstr(s): s = s.encode('utf-8', 'ignore') except: pass - return unicode(s, 'utf-8') + try: + return unicode(s) + except UnicodeDecodeError: + return unicode(s, 'utf-8') def str_esc_quote(s): """ From 796773bc67e173397f5d97ff8dd0ea96958b6d22 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 13:57:42 +0530 Subject: [PATCH 10/27] fix to update_after_submit --- cgi-bin/webnotes/model/doclist.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cgi-bin/webnotes/model/doclist.py b/cgi-bin/webnotes/model/doclist.py index 6e0b816974..b6f687991d 100644 --- a/cgi-bin/webnotes/model/doclist.py +++ b/cgi-bin/webnotes/model/doclist.py @@ -130,7 +130,7 @@ class DocList: webnotes.msgprint("""[Link Validation] Could not find the following values: %s. Please correct and resave. Document Not Saved.""" % ', '.join(err_list), raise_exception=1) - def update_timestamps(self): + def update_timestamps_and_docstatus(self): """ Update owner, creation, modified_by, modified, docstatus """ @@ -156,7 +156,7 @@ class DocList: self.check_permission() if check_links: self.check_links() - self.update_timestamps() + self.update_timestamps_and_docstatus() def run_method(self, method): """ @@ -240,6 +240,7 @@ class DocList: Update after submit - some values changed after submit """ self.to_docstatus = 1 + self.prepare_for_save(1) self.save_main() self.save_children() self.run_method('on_update_after_submit') From bcf64716125b28b0b5adc8a42cc0c264583d195a Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 14:02:08 +0530 Subject: [PATCH 11/27] fix to update_after_submit --- cgi-bin/webnotes/model/doclist.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cgi-bin/webnotes/model/doclist.py b/cgi-bin/webnotes/model/doclist.py index b6f687991d..cb70bc2df5 100644 --- a/cgi-bin/webnotes/model/doclist.py +++ b/cgi-bin/webnotes/model/doclist.py @@ -239,6 +239,8 @@ class DocList: """ Update after submit - some values changed after submit """ + if self.doc.docstatus != 1: + msgprint("Only to called after submit", raise_exception=1) self.to_docstatus = 1 self.prepare_for_save(1) self.save_main() From a1c43e51bbc8208f30cdcf7ab024d71de4a05a82 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 15:46:19 +0530 Subject: [PATCH 12/27] fixed attachments - now not reqd to save after attaching --- cgi-bin/webnotes/model/doclist.py | 2 +- cgi-bin/webnotes/utils/file_manager.py | 74 ++++++++++++++++++++++++-- cgi-bin/webnotes/widgets/form.py | 4 ++ js/form.compressed.js | 15 +++--- js/wn/widgets/form/attachments.js | 37 ++++++------- 5 files changed, 102 insertions(+), 30 deletions(-) diff --git a/cgi-bin/webnotes/model/doclist.py b/cgi-bin/webnotes/model/doclist.py index cb70bc2df5..2da46a795e 100644 --- a/cgi-bin/webnotes/model/doclist.py +++ b/cgi-bin/webnotes/model/doclist.py @@ -97,7 +97,7 @@ class DocList: """ from webnotes.model.meta import is_single - if (not is_single(self.doc.doctype)) and (not self.doc.fields.get('__islocal')): + if (not is_single(self.doc.doctype)) and (not cint(self.doc.fields.get('__islocal'))): tmp = webnotes.conn.sql(""" SELECT modified FROM `tab%s` WHERE name="%s" for update""" % (self.doc.doctype, self.doc.name)) diff --git a/cgi-bin/webnotes/utils/file_manager.py b/cgi-bin/webnotes/utils/file_manager.py index 26575ffd5f..cccc4f9a64 100644 --- a/cgi-bin/webnotes/utils/file_manager.py +++ b/cgi-bin/webnotes/utils/file_manager.py @@ -7,20 +7,86 @@ def upload(): dn = form.getvalue('docname') at_id = form.getvalue('at_id') + webnotes.response['type'] = 'iframe' + if not webnotes.form['filedata'].filename: + webnotes.response['result'] = """ + """ % dt + return + # save fid, fname = save_uploaded() - if fid: + # save it in the form + updated = add_file_list(dt, dn, fname, fid) + + if fid and updated: # refesh the form! + # with the new modified timestamp webnotes.response['result'] = """ - """ % (dt, dn, fid, fname.replace("'", "\\'"), at_id, dt, dn) + """ % { + 'dt': dt, + 'dn': dn, + 'fid': fid, + 'fname': fname.replace("'", "\\'"), + 'at_id': at_id, + 'mod': webnotes.conn.get_value(dt, dn, 'modified') + } # ------------------------------------------------------- +def add_file_list(dt, dn, fname, fid): + """ + udpate file_list attribute of the record + """ + import webnotes + try: + # get the old file_list + fl = webnotes.conn.sql("select file_list from `tab%s` where name=%s" % (dt, '%s'), dn)[0][0] or '' + if fl: + fl += '\n' + + # add new file id + fl += fname + ',' + fid + + # save + webnotes.conn.set_value(dt, dn, 'file_list', fl) + + return True + + except Exception, e: + webnotes.response['result'] = """ +""" % str(e) + + +def remove_file_list(dt, dn, fid): + """ + Remove fid from the give file_list + """ + import webnotes + + # get the old file_list + fl = webnotes.conn.sql("select file_list from `tab%s` where name=%s" % (dt, '%s'), dn)[0][0] or '' + new_fl = [] + fl = fl.split('\n') + for f in fl: + if f.split(',')[1]!=fid: + new_fl.append(f) + + # update the file_list + webnotes.conn.set_value(dt, dn, 'file_list', '\n'.join(new_fl)) + + # return the new timestamp + return webnotes.conn.get_value(dt, dn, 'modified') + def make_thumbnail(blob, size): from PIL import Image import cStringIO diff --git a/cgi-bin/webnotes/widgets/form.py b/cgi-bin/webnotes/widgets/form.py index fea70d61c0..7f5a325770 100644 --- a/cgi-bin/webnotes/widgets/form.py +++ b/cgi-bin/webnotes/widgets/form.py @@ -197,6 +197,7 @@ def runserverobj(): doclist = DocList() doclist.from_compressed(form.getvalue('docs'), dn) so = doclist.make_obj() + doclist.check_if_latest() check_guest_access(so.doc) @@ -288,6 +289,9 @@ def remove_attach(): fid = webnotes.form.getvalue('fid') webnotes.utils.file_manager.delete_file(fid, verbose=1) + + # remove from dt dn + return str(webnotes.utils.file_manager.remove_file_list(webnotes.form.getvalue('dt'), webnotes.form.getvalue('dn'), fid)) # Get Fields - Counterpart to $c_get_fields #=========================================================================================== diff --git a/js/form.compressed.js b/js/form.compressed.js index 32c2369634..41980e4ee4 100644 --- a/js/form.compressed.js +++ b/js/form.compressed.js @@ -474,7 +474,9 @@ for(var i=0;i Date: Thu, 11 Aug 2011 15:50:51 +0530 Subject: [PATCH 13/27] fixed attachments - now not reqd to save after attaching --- cgi-bin/webnotes/utils/file_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cgi-bin/webnotes/utils/file_manager.py b/cgi-bin/webnotes/utils/file_manager.py index cccc4f9a64..181403cb05 100644 --- a/cgi-bin/webnotes/utils/file_manager.py +++ b/cgi-bin/webnotes/utils/file_manager.py @@ -48,7 +48,7 @@ def add_file_list(dt, dn, fname, fid): import webnotes try: # get the old file_list - fl = webnotes.conn.sql("select file_list from `tab%s` where name=%s" % (dt, '%s'), dn)[0][0] or '' + fl = webnotes.conn.get_value(dt, dn, 'file_list') or '' if fl: fl += '\n' @@ -74,7 +74,7 @@ def remove_file_list(dt, dn, fid): import webnotes # get the old file_list - fl = webnotes.conn.sql("select file_list from `tab%s` where name=%s" % (dt, '%s'), dn)[0][0] or '' + fl = webnotes.conn.get_value(dt, dn, 'file_list') or '' new_fl = [] fl = fl.split('\n') for f in fl: From 0698438c746ef664a2c4a883b0c276420626728f Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 17:41:45 +0530 Subject: [PATCH 14/27] utf issue in recent --- cgi-bin/webnotes/profile.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index bb9a201da2..3fe1eec59d 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -176,12 +176,14 @@ class Profile: Update the user's `Recent` list with the given `dt` and `dn` """ conn = webnotes.conn + from webnotes.utils import cstr # get list of child tables, so we know what not to add in the recent list child_tables = [t[0] for t in conn.sql('select name from tabDocType where istable = 1')] + if not (dt in ['Print Format', 'Start Page', 'Event', 'ToDo Item', 'Search Criteria']) and not webnotes.is_testing and not (dt in child_tables): - r = webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '' - new_str = dt+'~~~'+dn + '\n' + r = cstr(webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '') + new_str = cstr(dt)+'~~~'+cstr(dn) + '\n' if new_str in r: r = r.replace(new_str, '') From bd95fda321cce6f6073db296aebd5de11b978adc Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 11 Aug 2011 17:42:19 +0530 Subject: [PATCH 15/27] profile, utf fix --- cgi-bin/webnotes/profile.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index dd135ee1ba..3fe1eec59d 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -150,10 +150,16 @@ class Profile: # get profile profile = webnotes.conn.sql("SELECT name, email, first_name, last_name FROM tabProfile WHERE name=%s OR email=%s",(self.name, self.name)) - + + profile_cols = [desc[0] for desc in webnotes.conn.sql("DESCRIBE tabProfile")] + if not profile: raise Exception, "Profile %s not found" % self.name - + elif 'registered' in profile_cols: + if not webnotes.conn.sql("SELECT registered FROM tabProfile WHERE name=%s", self.name)[0][0]: + # if an unregistered user tries to reset password + raise Exception, "You cannot reset your password as you have not completed registration. You need to complete registration using the link provided in the email." + # update tab Profile webnotes.conn.sql("UPDATE tabProfile SET password=password(%s) WHERE name=%s", (pwd, profile[0][0])) @@ -170,12 +176,14 @@ class Profile: Update the user's `Recent` list with the given `dt` and `dn` """ conn = webnotes.conn + from webnotes.utils import cstr # get list of child tables, so we know what not to add in the recent list child_tables = [t[0] for t in conn.sql('select name from tabDocType where istable = 1')] + if not (dt in ['Print Format', 'Start Page', 'Event', 'ToDo Item', 'Search Criteria']) and not webnotes.is_testing and not (dt in child_tables): - r = webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '' - new_str = dt+'~~~'+dn + '\n' + r = cstr(webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '') + new_str = cstr(dt)+'~~~'+cstr(dn) + '\n' if new_str in r: r = r.replace(new_str, '') From a9f947f305fa4c0a59aa64be028cccc7f070bc8b Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 12 Aug 2011 10:56:44 +0530 Subject: [PATCH 16/27] fixed issue for utf-8 --- cgi-bin/webnotes/db.py | 26 +++++++++++++++++++++++--- cgi-bin/webnotes/handler.py | 9 +++------ cgi-bin/webnotes/utils/__init__.py | 16 +++++----------- js/form.compressed.js | 2 +- js/utils/handler.js | 2 +- js/widgets/form/clientscriptAPI.js | 3 +-- js/wnf.compressed.js | 2 +- 7 files changed, 35 insertions(+), 25 deletions(-) diff --git a/cgi-bin/webnotes/db.py b/cgi-bin/webnotes/db.py index aae4d5b02d..8d175e317e 100644 --- a/cgi-bin/webnotes/db.py +++ b/cgi-bin/webnotes/db.py @@ -15,9 +15,6 @@ class Database: self.host = host or 'localhost' self.user = user or getattr(defs, 'default_db_name', '') - # password can be empty string - self.password = password==None and getattr(defs, 'db_password', '') or password - if ac_name: self.user = self.get_db_login(ac_name) or defs.default_db_name @@ -28,6 +25,8 @@ class Database: self.in_transaction = 0 self.transaction_writes = 0 self.testing_tables = [] + + self.password = self.get_db_password(ac_name, password) self.connect() if self.user != 'root': @@ -36,6 +35,27 @@ class Database: if webnotes.logger: webnotes.logger.debug('Database object initialized for:%s',self.user) + def get_db_password(self, db_name, password): + """ + Return db password. order of importance: + + 1. password + 2. defs.get_db_password() + 3. defs.db_password + """ + # password can be empty string + if password: + return password + + if hasattr(defs, 'get_db_password'): + return defs.get_db_password(db_name) + + if hasattr(defs, 'db_password'): + return defs.db_password + + else: + return '' + def get_db_login(self, ac_name): return getattr(defs,'db_name_map').get(ac_name, getattr(defs,'default_db_name')) diff --git a/cgi-bin/webnotes/handler.py b/cgi-bin/webnotes/handler.py index 760a96e8e4..f432c91ff8 100755 --- a/cgi-bin/webnotes/handler.py +++ b/cgi-bin/webnotes/handler.py @@ -410,17 +410,14 @@ else: except: # python 2.4 import simplejson as json - try: - str_out = json.dumps(webnotes.response) - except: - str_out = str(webnotes.response).replace(', None', ', ""') + str_out = json.dumps(webnotes.response) - if acceptsGzip and len(str_out)>512: + if acceptsGzip and 1 and len(str_out)>512: out_buf = compressBuf(str_out) print "Content-Encoding: gzip" print "Content-Length: %d" % (len(out_buf)) - print "Content-Type: text/html; Charset: ISO-8859-1" + print "Content-Type: text/html; charset: utf-8" # if there ar additional cookies defined during the request, add them here if webnotes.cookies or webnotes.add_cookies: diff --git a/cgi-bin/webnotes/utils/__init__.py b/cgi-bin/webnotes/utils/__init__.py index f8156046c2..1376ed7d41 100644 --- a/cgi-bin/webnotes/utils/__init__.py +++ b/cgi-bin/webnotes/utils/__init__.py @@ -287,19 +287,13 @@ def cstr(s): """ Convert to string """ - if s==None: + if type(s) in (str, unicode): + return s + elif s==None: return '' else: - if hasattr(s, 'encode'): - try: - s = s.encode('utf-8', 'ignore') - except: - pass - try: - return unicode(s) - except UnicodeDecodeError: - return unicode(s, 'utf-8') - + return str(s) + def str_esc_quote(s): """ Escape quotes diff --git a/js/form.compressed.js b/js/form.compressed.js index b46b5a7095..64ea3993ac 100644 --- a/js/form.compressed.js +++ b/js/form.compressed.js @@ -428,7 +428,7 @@ $c_get_values=function(args,doc,dt,dn,user_callback){var call_back=function(r,rt refresh_field(fl[i],dn,args.table_field);else refresh_field(fl[i]);}} $c('webnotes.widgets.form.get_fields',args,call_back);} -get_server_fields=function(method,arg,table_field,doc,dt,dn,allow_edit,call_back){if(!allow_edit)freeze('Fetching Data...');$c('runserverobj',args={'method':method,'docs':compress_doclist([doc]),'arg':arg},function(r,rt){if(r.message){var d=locals[dt][dn];var field_dict=eval('var a='+r.message+';a');for(var key in field_dict){d[key]=field_dict[key];if(table_field)refresh_field(key,d.name,table_field);else refresh_field(key);}} +get_server_fields=function(method,arg,table_field,doc,dt,dn,allow_edit,call_back){if(!allow_edit)freeze('Fetching Data...');$c('runserverobj',args={'method':method,'docs':compress_doclist([doc]),'arg':arg},function(r,rt){if(r.message){var d=locals[dt][dn];var field_dict=r.message;for(var key in field_dict){d[key]=field_dict[key];if(table_field)refresh_field(key,d.name,table_field);else refresh_field(key);}} if(call_back){doc=locals[doc.doctype][doc.name];call_back(doc,dt,dn);} if(!allow_edit)unfreeze();});} set_multiple=function(dt,dn,dict,table_field){var d=locals[dt][dn];for(var key in dict){d[key]=dict[key];if(table_field)refresh_field(key,d.name,table_field);else refresh_field(key);}} diff --git a/js/utils/handler.js b/js/utils/handler.js index f92bd70403..50a93a626b 100644 --- a/js/utils/handler.js +++ b/js/utils/handler.js @@ -42,7 +42,7 @@ function $c(command, args, fn, on_timeout, no_spinner, freeze_msg) { var rtxt = req.responseText; try { - var r = eval("var a="+rtxt+";a"); + var r = JSON.parse(rtxt); } catch(e) { alert('Handler Exception:' + rtxt); return; diff --git a/js/widgets/form/clientscriptAPI.js b/js/widgets/form/clientscriptAPI.js index ccf64c58c4..f8f37ab06a 100644 --- a/js/widgets/form/clientscriptAPI.js +++ b/js/widgets/form/clientscriptAPI.js @@ -24,8 +24,7 @@ get_server_fields = function(method, arg, table_field, doc, dt, dn, allow_edit, function(r, rt) { if (r.message) { var d = locals[dt][dn]; - var field_dict = eval('var a='+r.message+';a'); - + var field_dict = r.message; for(var key in field_dict) { d[key] = field_dict[key]; if (table_field) refresh_field(key, d.name, table_field); diff --git a/js/wnf.compressed.js b/js/wnf.compressed.js index 11c20e1ccf..95ecd051a4 100644 --- a/js/wnf.compressed.js +++ b/js/wnf.compressed.js @@ -250,7 +250,7 @@ unfreeze();return false;}} var pending_req=0;function newHttpReq(){if(!isIE) var r=new XMLHttpRequest();else if(window.ActiveXObject) var r=new ActiveXObject("Microsoft.XMLHTTP");return r;} -function $c(command,args,fn,on_timeout,no_spinner,freeze_msg){var req=newHttpReq();ret_fn=function(){if(checkResponse(req,on_timeout,no_spinner,freeze_msg)){if(!no_spinner)hide_loading();var rtxt=req.responseText;try{var r=eval("var a="+rtxt+";a");}catch(e){alert('Handler Exception:'+rtxt);return;} +function $c(command,args,fn,on_timeout,no_spinner,freeze_msg){var req=newHttpReq();ret_fn=function(){if(checkResponse(req,on_timeout,no_spinner,freeze_msg)){if(!no_spinner)hide_loading();var rtxt=req.responseText;try{var r=JSON.parse(rtxt);}catch(e){alert('Handler Exception:'+rtxt);return;} if(freeze_msg)unfreeze();if(!validate_session(r,rtxt))return;if(r.exc){errprint(r.exc);};if(r.server_messages){msgprint(r.server_messages);};if(r.docs){LocalDB.sync(r.docs);} saveAllowed=true;if(fn)fn(r,rtxt);}} req.onreadystatechange=ret_fn;req.open("POST",outUrl,true);req.setRequestHeader("ENCTYPE","multipart/form-data");req.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");args['cmd']=command;req.send(makeArgString(args));if(!no_spinner)set_loading();if(freeze_msg)freeze(freeze_msg,1);} From 36e7aeb2a552c5380ddf3fd768694fa546ab954e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 12 Aug 2011 11:26:54 +0530 Subject: [PATCH 17/27] doclist.py: catch all if docname does match doc (? unidentified issue) --- cgi-bin/webnotes/model/doclist.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cgi-bin/webnotes/model/doclist.py b/cgi-bin/webnotes/model/doclist.py index 2da46a795e..ee156d6c23 100644 --- a/cgi-bin/webnotes/model/doclist.py +++ b/cgi-bin/webnotes/model/doclist.py @@ -68,6 +68,10 @@ class DocList: self.doc = d else: self.children.append(d) + + # catch all if no self.doc + if not self.doc: + self.doc, self.children = self.docs[0], self.docs[1:] def make_obj(self): """ From dc1d4069661bcdcf31b9780f5fbfd3b3a067fe5e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 12 Aug 2011 11:29:30 +0530 Subject: [PATCH 18/27] doclist.py: catch all if docname does match doc (? unidentified issue) --- cgi-bin/webnotes/model/doclist.py | 1 + cgi-bin/webnotes/profile.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cgi-bin/webnotes/model/doclist.py b/cgi-bin/webnotes/model/doclist.py index ee156d6c23..c8df02660a 100644 --- a/cgi-bin/webnotes/model/doclist.py +++ b/cgi-bin/webnotes/model/doclist.py @@ -62,6 +62,7 @@ class DocList: self.doc, self.children = self.docs[0], self.docs[1:] else: + self.doc = None self.children = [] for d in self.docs: if d.name == docname: diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index 3fe1eec59d..72b5901c42 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -183,7 +183,7 @@ class Profile: if not (dt in ['Print Format', 'Start Page', 'Event', 'ToDo Item', 'Search Criteria']) and not webnotes.is_testing and not (dt in child_tables): r = cstr(webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '') - new_str = cstr(dt)+'~~~'+cstr(dn) + '\n' + new_str = dt+'~~~'+dn + '\n' if new_str in r: r = r.replace(new_str, '') From 1638de5295b316ebff0c39d0ce9766cc8f1b1427 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 12 Aug 2011 11:30:45 +0530 Subject: [PATCH 19/27] profile.py: codec --- cgi-bin/webnotes/profile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index 72b5901c42..1c4ac13f01 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -182,7 +182,7 @@ class Profile: child_tables = [t[0] for t in conn.sql('select name from tabDocType where istable = 1')] if not (dt in ['Print Format', 'Start Page', 'Event', 'ToDo Item', 'Search Criteria']) and not webnotes.is_testing and not (dt in child_tables): - r = cstr(webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '') + r = webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '' new_str = dt+'~~~'+dn + '\n' if new_str in r: r = r.replace(new_str, '') From 67ef4b2ea1a73b175244fd0991720e67491c4c49 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 12 Aug 2011 11:41:49 +0530 Subject: [PATCH 20/27] fixed old recent docs --- cgi-bin/webnotes/profile.py | 25 ++++++++++++++++++------- js/webpage/wntoolbar.js | 26 +++++++++++++++----------- js/wnf.compressed.js | 6 ++++-- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index 1c4ac13f01..963dda4090 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -177,21 +177,32 @@ class Profile: """ conn = webnotes.conn from webnotes.utils import cstr + import json # get list of child tables, so we know what not to add in the recent list child_tables = [t[0] for t in conn.sql('select name from tabDocType where istable = 1')] if not (dt in ['Print Format', 'Start Page', 'Event', 'ToDo Item', 'Search Criteria']) and not webnotes.is_testing and not (dt in child_tables): r = webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '' - new_str = dt+'~~~'+dn + '\n' - if new_str in r: - r = r.replace(new_str, '') + + # clear old style (to be removed) + if '~~' in r: r = '' + + rdl = json.loads(r or '[]') + new_rd = [dt, dn] + + # clear if exists + for i in range(len(rdl)): + rd = rdl[i] + if rd==new_rd: + del rdl[i] - self.recent = new_str + r - - if len(self.recent.split('\n')) > 50: - self.recent = '\n'.join(self.recent.split('\n')[:50]) + rdl.append(new_rd) + if len(rdl) > 20: + rdl = rdl[:20] + self.recent = json.dumps(rdl) + webnotes.conn.sql("update tabProfile set recent_documents=%s where name=%s", (self.recent, self.name)) def load_profile(self): diff --git a/js/webpage/wntoolbar.js b/js/webpage/wntoolbar.js index 7fbfede1f4..b7bc287a50 100644 --- a/js/webpage/wntoolbar.js +++ b/js/webpage/wntoolbar.js @@ -104,23 +104,27 @@ function WNToolbar(parent) { if(it)$dh(it); if(pscript.on_recent_update)pscript.on_recent_update(); } - // add menu items - var rlist = profile.recent.split('\n'); - var m = rlist.length; - if(m>15)m=15; - for (var i=0;i15)m=15; + for (var i=0;i'+tdn+'' +''+get_doctype_label(dt)+'';var mi=me.menu.add_item('Recent',rec_label,fn,on_top);mi.dt=dt;mi.dn=dn;this.items[dt+'-'+dn]=mi;if(pscript.on_recent_update)pscript.on_recent_update();}} this.rdocs.remove=function(dt,dn){var it=me.rdocs.items[dt+'-'+dn];if(it)$dh(it);if(pscript.on_recent_update)pscript.on_recent_update();} -var rlist=profile.recent.split('\n');var m=rlist.length;if(m>15)m=15;for(var i=0;i15)m=15;for(var i=0;i Date: Tue, 16 Aug 2011 09:08:13 +0530 Subject: [PATCH 21/27] fixes to install + recent --- cgi-bin/webnotes/install_lib/install.py | 14 +++++++++++--- cgi-bin/webnotes/profile.py | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cgi-bin/webnotes/install_lib/install.py b/cgi-bin/webnotes/install_lib/install.py index c270b2059c..68c9fbd2fa 100755 --- a/cgi-bin/webnotes/install_lib/install.py +++ b/cgi-bin/webnotes/install_lib/install.py @@ -98,9 +98,17 @@ class Installer: webnotes.conn.commit() - # - # main script to create a database from - # + def get_db_password(self, db_name): + """ + Get the db_password by method + """ + import webnotes.defs + if hasattr(webnotes.defs, 'get_db_password'): + return webnotes.defs.get_db_password(db_name) + if hasattr(webnotes.defs, 'db_password'): + return webnotes.defs.db_password + return '' + def import_from_db(self, target, source_path='', password = 'admin', verbose=0): """ a very simplified version, just for the time being..will eventually be deprecated once the framework stabilizes. diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index 963dda4090..139243cbbd 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -196,6 +196,7 @@ class Profile: rd = rdl[i] if rd==new_rd: del rdl[i] + break rdl.append(new_rd) if len(rdl) > 20: From 9c3a02677f437b27303305eefe62effda2a5e87a Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 16 Aug 2011 09:56:00 +0530 Subject: [PATCH 22/27] encoding friendly csv output --- .../utils/{ => jslib}/jsdependency.py | 0 cgi-bin/webnotes/utils/{ => jslib}/jsmin.py | 0 .../webnotes/utils/{ => jslib}/jsnamespace.py | 0 .../webnotes/utils/{ => jslib}/jstimestamp.py | 0 cgi-bin/webnotes/widgets/form.py | 23 +++++++------- cgi-bin/webnotes/widgets/query_builder.py | 31 +++++++++---------- 6 files changed, 25 insertions(+), 29 deletions(-) rename cgi-bin/webnotes/utils/{ => jslib}/jsdependency.py (100%) rename cgi-bin/webnotes/utils/{ => jslib}/jsmin.py (100%) rename cgi-bin/webnotes/utils/{ => jslib}/jsnamespace.py (100%) rename cgi-bin/webnotes/utils/{ => jslib}/jstimestamp.py (100%) diff --git a/cgi-bin/webnotes/utils/jsdependency.py b/cgi-bin/webnotes/utils/jslib/jsdependency.py similarity index 100% rename from cgi-bin/webnotes/utils/jsdependency.py rename to cgi-bin/webnotes/utils/jslib/jsdependency.py diff --git a/cgi-bin/webnotes/utils/jsmin.py b/cgi-bin/webnotes/utils/jslib/jsmin.py similarity index 100% rename from cgi-bin/webnotes/utils/jsmin.py rename to cgi-bin/webnotes/utils/jslib/jsmin.py diff --git a/cgi-bin/webnotes/utils/jsnamespace.py b/cgi-bin/webnotes/utils/jslib/jsnamespace.py similarity index 100% rename from cgi-bin/webnotes/utils/jsnamespace.py rename to cgi-bin/webnotes/utils/jslib/jsnamespace.py diff --git a/cgi-bin/webnotes/utils/jstimestamp.py b/cgi-bin/webnotes/utils/jslib/jstimestamp.py similarity index 100% rename from cgi-bin/webnotes/utils/jstimestamp.py rename to cgi-bin/webnotes/utils/jslib/jstimestamp.py diff --git a/cgi-bin/webnotes/widgets/form.py b/cgi-bin/webnotes/widgets/form.py index 7f5a325770..6eddede16f 100644 --- a/cgi-bin/webnotes/widgets/form.py +++ b/cgi-bin/webnotes/widgets/form.py @@ -214,19 +214,18 @@ def runserverobj(): def make_csv_output(res, dt): import webnotes - from webnotes.utils import getCSVelement - - txt = [] - if type(res)==list: - for r in res: - txt.append(','.join([getCSVelement(i) for i in r])) - - txt = '\n'.join(txt) - else: - txt = 'Output was not in list format\n' + r - - webnotes.response['result'] = txt + from cStringIO import StringIO + import csv + + f = StringIO() + writer = csv.writer(f) + for r in res: + writer.writerow(r) + + f.seek(0) + + webnotes.response['result'] = f.read() webnotes.response['type'] = 'csv' webnotes.response['doctype'] = dt.replace(' ','') diff --git a/cgi-bin/webnotes/widgets/query_builder.py b/cgi-bin/webnotes/widgets/query_builder.py index cf272434e3..72e320cd70 100644 --- a/cgi-bin/webnotes/widgets/query_builder.py +++ b/cgi-bin/webnotes/widgets/query_builder.py @@ -294,7 +294,7 @@ def runquery(q='', ret=0, from_export=0): # ==================================================================== def runquery_csv(): - from webnotes.utils import getCSVelement + global out # run query res = runquery(from_export = 1) @@ -312,22 +312,19 @@ def runquery_csv(): # Headings heads = [] - for h in out['colnames']: - heads.append(getCSVelement(h)) - if form.has_key('colnames'): - for h in form.getvalue('colnames').split(','): - heads.append(getCSVelement(h)) - - # Output dataset - dset = [rep_name, ''] - if heads: - dset.append(','.join(heads)) - # Data - for r in out['values']: - dset.append(','.join([getCSVelement(i) for i in r])) - - txt = '\n'.join(dset) - out['result'] = txt + rows = [[rep_name], out['colnames']] + out['values'] + + from cStringIO import StringIO + import csv + + f = StringIO() + writer = csv.writer(f) + for r in rows: + writer.writerow(r) + + f.seek(0) + out['result'] = f.read() out['type'] = 'csv' out['doctype'] = rep_name + From d109285c87b2355296a979afe2016bf4d8bf496f Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 17 Aug 2011 11:23:27 +0530 Subject: [PATCH 23/27] added latest version of jqplot and $.require --- .gitignore | 1 + cgi-bin/core/doctype/module_def/module_def.py | 2 +- css/default.css | 75 +- css/jqplot.css | 75 +- .../jqplot.BezierCurveRenderer.js | 312 +++++ .../jqplot.BezierCurveRenderer.min.js | 30 + .../jqplot-plugins/jqplot.barRenderer.js | 381 +++++- .../jqplot-plugins/jqplot.barRenderer.min.js | 24 +- .../jqplot-plugins/jqplot.blockRenderer.js | 234 ++++ .../jqplot.blockRenderer.min.js | 30 + .../jqplot-plugins/jqplot.bubbleRenderer.js | 754 ++++++++++++ .../jqplot.bubbleRenderer.min.js | 30 + .../jqplot.canvasAxisLabelRenderer.js | 93 +- .../jqplot.canvasAxisLabelRenderer.min.js | 24 +- .../jqplot.canvasAxisTickRenderer.js | 107 +- .../jqplot.canvasAxisTickRenderer.min.js | 24 +- .../jqplot-plugins/jqplot.canvasOverlay.js | 705 +++++++++++ .../jqplot.canvasOverlay.min.js | 30 + .../jqplot.canvasTextRenderer.js | 30 +- .../jqplot.canvasTextRenderer.min.js | 24 +- .../jqplot.categoryAxisRenderer.js | 436 ++++++- .../jqplot.categoryAxisRenderer.min.js | 24 +- js/jquery/jqplot-plugins/jqplot.ciParser.js | 115 ++ .../jqplot-plugins/jqplot.ciParser.min.js | 30 + js/jquery/jqplot-plugins/jqplot.cursor.js | 405 +++++-- js/jquery/jqplot-plugins/jqplot.cursor.min.js | 24 +- .../jqplot-plugins/jqplot.dateAxisRenderer.js | 204 +++- .../jqplot.dateAxisRenderer.min.js | 24 +- .../jqplot-plugins/jqplot.donutRenderer.js | 910 +++++++++++++++ .../jqplot.donutRenderer.min.js | 30 + js/jquery/jqplot-plugins/jqplot.dragable.js | 39 +- .../jqplot-plugins/jqplot.dragable.min.js | 24 +- .../jqplot.enhancedLegendRenderer.js | 199 ++++ .../jqplot.enhancedLegendRenderer.min.js | 30 + .../jqplot-plugins/jqplot.funnelRenderer.js | 938 +++++++++++++++ .../jqplot.funnelRenderer.min.js | 30 + .../jqplot-plugins/jqplot.highlighter.js | 104 +- .../jqplot-plugins/jqplot.highlighter.min.js | 24 +- js/jquery/jqplot-plugins/jqplot.json2.js | 475 ++++++++ js/jquery/jqplot-plugins/jqplot.json2.min.js | 30 + .../jqplot-plugins/jqplot.logAxisRenderer.js | 48 +- .../jqplot.logAxisRenderer.min.js | 24 +- .../jqplot.mekkoAxisRenderer.js | 45 +- .../jqplot.mekkoAxisRenderer.min.js | 24 +- .../jqplot-plugins/jqplot.mekkoRenderer.js | 192 ++- .../jqplot.mekkoRenderer.min.js | 24 +- .../jqplot.meterGaugeRenderer.js | 1033 +++++++++++++++++ .../jqplot.meterGaugeRenderer.min.js | 30 + .../jqplot-plugins/jqplot.ohlcRenderer.js | 53 +- .../jqplot-plugins/jqplot.ohlcRenderer.min.js | 24 +- .../jqplot-plugins/jqplot.pieRenderer.js | 761 ++++++++++-- .../jqplot-plugins/jqplot.pieRenderer.min.js | 24 +- .../jqplot-plugins/jqplot.pointLabels.js | 180 +-- .../jqplot-plugins/jqplot.pointLabels.js.orig | 273 ----- .../jqplot-plugins/jqplot.pointLabels.min.js | 24 +- js/jquery/jqplot-plugins/jqplot.trendline.js | 34 +- .../jqplot-plugins/jqplot.trendline.min.js | 24 +- js/jquery/jquery.corners.min.js | 7 - js/jquery/jquery.jqplot.min.js | 24 +- js/jquery/jquery.tools.min.js | 35 - js/utils/handler.js | 59 +- js/wnf.compressed.js | 6 +- 62 files changed, 9064 insertions(+), 964 deletions(-) create mode 100644 js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.js create mode 100644 js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.blockRenderer.js create mode 100644 js/jquery/jqplot-plugins/jqplot.blockRenderer.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.bubbleRenderer.js create mode 100644 js/jquery/jqplot-plugins/jqplot.bubbleRenderer.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.canvasOverlay.js create mode 100644 js/jquery/jqplot-plugins/jqplot.canvasOverlay.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.ciParser.js create mode 100644 js/jquery/jqplot-plugins/jqplot.ciParser.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.donutRenderer.js create mode 100644 js/jquery/jqplot-plugins/jqplot.donutRenderer.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.enhancedLegendRenderer.js create mode 100644 js/jquery/jqplot-plugins/jqplot.enhancedLegendRenderer.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.funnelRenderer.js create mode 100644 js/jquery/jqplot-plugins/jqplot.funnelRenderer.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.json2.js create mode 100644 js/jquery/jqplot-plugins/jqplot.json2.min.js create mode 100644 js/jquery/jqplot-plugins/jqplot.meterGaugeRenderer.js create mode 100644 js/jquery/jqplot-plugins/jqplot.meterGaugeRenderer.min.js delete mode 100644 js/jquery/jqplot-plugins/jqplot.pointLabels.js.orig delete mode 100644 js/jquery/jquery.corners.min.js delete mode 100644 js/jquery/jquery.tools.min.js diff --git a/.gitignore b/.gitignore index 1c6dbb5761..e158c010fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.pyc *.comp.js *.DS_Store +user_files defs.py diff --git a/cgi-bin/core/doctype/module_def/module_def.py b/cgi-bin/core/doctype/module_def/module_def.py index 9d78fc68a5..b6e6cd5c2e 100644 --- a/cgi-bin/core/doctype/module_def/module_def.py +++ b/cgi-bin/core/doctype/module_def/module_def.py @@ -43,7 +43,7 @@ class DocType: r.save(1) def on_update(self, from_update=0): - import webnotes.defs + from webnotes import defs from webnotes.utils.transfer import in_transfer if (not in_transfer) and getattr(defs,'developer_mode', 0): diff --git a/css/default.css b/css/default.css index 1206c8fe72..13229518d5 100644 --- a/css/default.css +++ b/css/default.css @@ -1244,13 +1244,11 @@ ul.box_tabs li.box_tab_selected a { /* background:url("../images/ui/rc/tab-right-CCC.gif") no-repeat right top; */ } -/******* jqPlot ***********/ - /*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ .jqplot-target { position: relative; color: #666666; - font-family: Arial, Helvetica, sans-serif; + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; font-size: 1em; /* height: 300px; width: 400px;*/ @@ -1308,6 +1306,15 @@ ul.box_tabs li.box_tab_selected a { text-align: right; } +.jqplot-yaxis-tick.jqplot-breakTick { + right: -20px; + margin-right: 0px; + padding:1px 5px 1px 5px; +/* background-color: white;*/ + z-index: 2; + font-size: 1.5em; +} + .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { left: 0px; /* initial position untill tick is drawn in proper place */ @@ -1317,6 +1324,15 @@ ul.box_tabs li.box_tab_selected a { text-align: left; } +.jqplot-meterGauge-tick { + font-size: 0.75em; + color: #999999; +} + +.jqplot-meterGauge-label { + font-size: 1em; + color: #999999; +} .jqplot-xaxis-label { margin-top: 10px; font-size: 11pt; @@ -1342,6 +1358,13 @@ ul.box_tabs li.box_tab_selected a { position: absolute; } +table.jqplot-table-legend { + margin-top: 12px; + margin-bottom: 12px; + margin-left: 12px; + margin-right: 12px; +} + table.jqplot-table-legend, table.jqplot-cursor-legend { background-color: rgba(255,255,255,0.6); border: 1px solid #cccccc; @@ -1353,18 +1376,22 @@ td.jqplot-table-legend { vertical-align:middle; } +td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { + cursor: pointer; +} + td.jqplot-table-legend > div { - border:1px solid #cccccc; - padding:0.2em; + border: 1px solid #cccccc; + padding:1px; } div.jqplot-table-legend-swatch { width:0px; height:0px; - border-top-width: 0.35em; - border-bottom-width: 0.35em; - border-left-width: 0.6em; - border-right-width: 0.6em; + border-top-width: 5px; + border-bottom-width: 5px; + border-left-width: 6px; + border-right-width: 6px; border-top-style: solid; border-bottom-style: solid; border-left-style: solid; @@ -1402,6 +1429,7 @@ table.jqplot-cursor-tooltip { .jqplot-point-label { font-size: 0.75em; + z-index: 2; } td.jqplot-cursor-legend-swatch { @@ -1414,6 +1442,35 @@ width:1.2em; height:0.7em; } +.jqplot-error { +/* Styles added to the plot target container when there is an error go here.*/ + text-align: center; +} + +.jqplot-error-message { +/* Styling of the custom error message div goes here.*/ + position: relative; + top: 46%; + display: inline-block; +} + +div.jqplot-bubble-label { + font-size: 0.8em; +/* background: rgba(90%, 90%, 90%, 0.15);*/ + padding-left: 2px; + padding-right: 2px; + color: rgb(20%, 20%, 20%); +} + +div.jqplot-bubble-label.jqplot-bubble-label-highlight { + background: rgba(90%, 90%, 90%, 0.7); +} + +div.jqplot-noData-container { + text-align: center; + background-color: rgba(96%, 96%, 96%, 0.3); +} + /** general icons **/ diff --git a/css/jqplot.css b/css/jqplot.css index c1882b5286..c9bf6f923b 100644 --- a/css/jqplot.css +++ b/css/jqplot.css @@ -1,10 +1,8 @@ -/******* jqPlot ***********/ - /*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ .jqplot-target { position: relative; color: #666666; - font-family: Arial, Helvetica, sans-serif; + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; font-size: 1em; /* height: 300px; width: 400px;*/ @@ -62,6 +60,15 @@ text-align: right; } +.jqplot-yaxis-tick.jqplot-breakTick { + right: -20px; + margin-right: 0px; + padding:1px 5px 1px 5px; +/* background-color: white;*/ + z-index: 2; + font-size: 1.5em; +} + .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { left: 0px; /* initial position untill tick is drawn in proper place */ @@ -71,6 +78,15 @@ text-align: left; } +.jqplot-meterGauge-tick { + font-size: 0.75em; + color: #999999; +} + +.jqplot-meterGauge-label { + font-size: 1em; + color: #999999; +} .jqplot-xaxis-label { margin-top: 10px; font-size: 11pt; @@ -96,6 +112,13 @@ position: absolute; } +table.jqplot-table-legend { + margin-top: 12px; + margin-bottom: 12px; + margin-left: 12px; + margin-right: 12px; +} + table.jqplot-table-legend, table.jqplot-cursor-legend { background-color: rgba(255,255,255,0.6); border: 1px solid #cccccc; @@ -107,18 +130,22 @@ td.jqplot-table-legend { vertical-align:middle; } +td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { + cursor: pointer; +} + td.jqplot-table-legend > div { - border:1px solid #cccccc; - padding:0.2em; + border: 1px solid #cccccc; + padding:1px; } div.jqplot-table-legend-swatch { width:0px; height:0px; - border-top-width: 0.35em; - border-bottom-width: 0.35em; - border-left-width: 0.6em; - border-right-width: 0.6em; + border-top-width: 5px; + border-bottom-width: 5px; + border-left-width: 6px; + border-right-width: 6px; border-top-style: solid; border-bottom-style: solid; border-left-style: solid; @@ -156,6 +183,7 @@ table.jqplot-cursor-tooltip { .jqplot-point-label { font-size: 0.75em; + z-index: 2; } td.jqplot-cursor-legend-swatch { @@ -167,3 +195,32 @@ div.jqplot-cursor-legend-swatch { width:1.2em; height:0.7em; } + +.jqplot-error { +/* Styles added to the plot target container when there is an error go here.*/ + text-align: center; +} + +.jqplot-error-message { +/* Styling of the custom error message div goes here.*/ + position: relative; + top: 46%; + display: inline-block; +} + +div.jqplot-bubble-label { + font-size: 0.8em; +/* background: rgba(90%, 90%, 90%, 0.15);*/ + padding-left: 2px; + padding-right: 2px; + color: rgb(20%, 20%, 20%); +} + +div.jqplot-bubble-label.jqplot-bubble-label-highlight { + background: rgba(90%, 90%, 90%, 0.7); +} + +div.jqplot-noData-container { + text-align: center; + background-color: rgba(96%, 96%, 96%, 0.3); +} diff --git a/js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.js b/js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.js new file mode 100644 index 0000000000..a1d29666b9 --- /dev/null +++ b/js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.js @@ -0,0 +1,312 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.0b2_r792 + * + * Copyright (c) 2009-2011 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + // Class: $.jqplot.BezierCurveRenderer.js + // Renderer which draws lines as stacked bezier curves. + // Data for the line will not be specified as an array of + // [x, y] data point values, but as a an array of [start piont, bezier curve] + // So, the line is specified as: [[xstart, ystart], [cp1x, cp1y, cp2x, cp2y, xend, yend]]. + $.jqplot.BezierCurveRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.BezierCurveRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.BezierCurveRenderer.prototype.constructor = $.jqplot.BezierCurveRenderer; + + + // Method: setGridData + // converts the user data values to grid coordinates and stores them + // in the gridData array. + // Called with scope of a series. + $.jqplot.BezierCurveRenderer.prototype.setGridData = function(plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + // this._plotData should be same as this.data + var data = this.data; + this.gridData = []; + this._prevGridData = []; + // if seriesIndex = 0, fill to x axis. + // if seriesIndex > 0, fill to previous series data. + var idx = this.index; + if (data.length == 2) { + if (idx == 0) { + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])], + [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + else { + if (idx == 0) { + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])], + [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + }; + + // Method: makeGridData + // converts any arbitrary data values to grid coordinates and + // returns them. This method exists so that plugins can use a series' + // linerenderer to generate grid data points without overwriting the + // grid data associated with that series. + // Called with scope of a series. + $.jqplot.BezierCurveRenderer.prototype.makeGridData = function(data, plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var gd = []; + var pgd = []; + // if seriesIndex = 0, fill to x axis. + // if seriesIndex > 0, fill to previous series data. + var idx = this.index; + if (data.length == 2) { + if (idx == 0) { + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])], + [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + else { + if (idx == 0) { + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])], + [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + return gd; + }; + + + // called within scope of series. + $.jqplot.BezierCurveRenderer.prototype.draw = function(ctx, gd, options) { + var i; + ctx.save(); + if (gd.length) { + if (this.showLine) { + ctx.save(); + var opts = (options != null) ? options : {}; + ctx.fillStyle = opts.fillStyle || this.color; + ctx.beginPath(); + ctx.moveTo(gd[0][0], gd[0][1]); + ctx.bezierCurveTo(gd[1][0], gd[1][1], gd[1][2], gd[1][3], gd[1][4], gd[1][5]); + ctx.lineTo(gd[2][0], gd[2][1]); + if (gd[3].length == 2) { + ctx.lineTo(gd[3][0], gd[3][1]); + } + else { + ctx.bezierCurveTo(gd[3][0], gd[3][1], gd[3][2], gd[3][3], gd[3][4], gd[3][5]); + } + ctx.closePath(); + ctx.fill(); + ctx.restore(); + } + } + + ctx.restore(); + }; + + $.jqplot.BezierCurveRenderer.prototype.drawShadow = function(ctx, gd, options) { + // This is a no-op, shadows drawn with lines. + }; + + $.jqplot.BezierAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.BezierAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.BezierAxisRenderer.prototype.constructor = $.jqplot.BezierAxisRenderer; + + + // Axes on a plot with Bezier Curves + $.jqplot.BezierAxisRenderer.prototype.init = function(options){ + $.extend(true, this, options); + var db = this._dataBounds; + // Go through all the series attached to this axis and find + // the min/max bounds for this axis. + for (var i=0; i db.max || db.max == null) { + db.max = d[j][0]; + } + } + else { + if (d[j][1] < db.min || db.min == null) { + db.min = d[j][1]; + } + if (d[j][1] > db.max || db.max == null) { + db.max = d[j][1]; + } + } + } + } + else { + if (this.name == 'xaxis' || this.name == 'x2axis') { + if (d[0][0] < db.min || db.min == null) { + db.min = d[0][0]; + } + if (d[0][0] > db.max || db.max == null) { + db.max = d[0][0]; + } + for (var j=0; j<5; j+=2) { + if (d[1][j] < db.min || db.min == null) { + db.min = d[1][j]; + } + if (d[1][j] > db.max || db.max == null) { + db.max = d[1][j]; + } + } + } + else { + if (d[0][1] < db.min || db.min == null) { + db.min = d[0][1]; + } + if (d[0][1] > db.max || db.max == null) { + db.max = d[0][1]; + } + for (var j=1; j<6; j+=2) { + if (d[1][j] < db.min || db.min == null) { + db.min = d[1][j]; + } + if (d[1][j] > db.max || db.max == null) { + db.max = d[1][j]; + } + } + } + } + } + }; + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = $.extend(true, {pad:0}, options.axesDefaults); + options.legend = $.extend(true, {placement:'outside'}, options.legend); + // only set these if there is a pie series + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.BezierCurveRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.BezierCurveRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.BezierAxisRenderer; + } + } + + $.jqplot.preInitHooks.push(preInit); + +})(jQuery); \ No newline at end of file diff --git a/js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.min.js b/js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.min.js new file mode 100644 index 0000000000..246b747952 --- /dev/null +++ b/js/jquery/jqplot-plugins/jqplot.BezierCurveRenderer.min.js @@ -0,0 +1,30 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.0b2_r792 + * + * Copyright (c) 2009-2011 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function(b){b.jqplot.BezierCurveRenderer=function(){b.jqplot.LineRenderer.call(this)};b.jqplot.BezierCurveRenderer.prototype=new b.jqplot.LineRenderer();b.jqplot.BezierCurveRenderer.prototype.constructor=b.jqplot.BezierCurveRenderer;b.jqplot.BezierCurveRenderer.prototype.setGridData=function(h){var e=this._xaxis.series_u2p;var g=this._yaxis.series_u2p;var f=this.data;this.gridData=[];this._prevGridData=[];var d=this.index;if(f.length==2){if(d==0){this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[1][2]),g.call(this._yaxis,f[1][3]),e.call(this._xaxis,f[1][4]),g.call(this._yaxis,f[1][5])],[e.call(this._xaxis,f[1][4]),g.call(this._yaxis,this._yaxis.min)],[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,this._yaxis.min)]]}else{var c=h.series[d-1].data;this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[1][2]),g.call(this._yaxis,f[1][3]),e.call(this._xaxis,f[1][4]),g.call(this._yaxis,f[1][5])],[e.call(this._xaxis,c[1][4]),g.call(this._yaxis,c[1][5])],[e.call(this._xaxis,c[1][2]),g.call(this._yaxis,c[1][3]),e.call(this._xaxis,c[1][0]),g.call(this._yaxis,c[1][1]),e.call(this._xaxis,c[0][0]),g.call(this._yaxis,c[0][1])]]}}else{if(d==0){this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[2][0]),g.call(this._yaxis,f[2][1]),e.call(this._xaxis,f[3][0]),g.call(this._yaxis,f[3][1])],[e.call(this._xaxis,f[3][1]),g.call(this._yaxis,this._yaxis.min)],[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,this._yaxis.min)]]}else{var c=h.series[d-1].data;this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[2][0]),g.call(this._yaxis,f[2][1]),e.call(this._xaxis,f[3][0]),g.call(this._yaxis,f[3][1])],[e.call(this._xaxis,c[3][0]),g.call(this._yaxis,c[3][1])],[e.call(this._xaxis,c[2][0]),g.call(this._yaxis,c[2][1]),e.call(this._xaxis,c[1][0]),g.call(this._yaxis,c[1][1]),e.call(this._xaxis,c[0][0]),g.call(this._yaxis,c[0][1])]]}}};b.jqplot.BezierCurveRenderer.prototype.makeGridData=function(g,i){var f=this._xaxis.series_u2p;var h=this._yaxis.series_u2p;var e=[];var j=[];var d=this.index;if(g.length==2){if(d==0){e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[1][2]),h.call(this._yaxis,g[1][3]),f.call(this._xaxis,g[1][4]),h.call(this._yaxis,g[1][5])],[f.call(this._xaxis,g[1][4]),h.call(this._yaxis,this._yaxis.min)],[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,this._yaxis.min)]]}else{var c=i.series[d-1].data;e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[1][2]),h.call(this._yaxis,g[1][3]),f.call(this._xaxis,g[1][4]),h.call(this._yaxis,g[1][5])],[f.call(this._xaxis,c[1][4]),h.call(this._yaxis,c[1][5])],[f.call(this._xaxis,c[1][2]),h.call(this._yaxis,c[1][3]),f.call(this._xaxis,c[1][0]),h.call(this._yaxis,c[1][1]),f.call(this._xaxis,c[0][0]),h.call(this._yaxis,c[0][1])]]}}else{if(d==0){e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[2][0]),h.call(this._yaxis,g[2][1]),f.call(this._xaxis,g[3][0]),h.call(this._yaxis,g[3][1])],[f.call(this._xaxis,g[3][1]),h.call(this._yaxis,this._yaxis.min)],[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,this._yaxis.min)]]}else{var c=i.series[d-1].data;e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[2][0]),h.call(this._yaxis,g[2][1]),f.call(this._xaxis,g[3][0]),h.call(this._yaxis,g[3][1])],[f.call(this._xaxis,c[3][0]),h.call(this._yaxis,c[3][1])],[f.call(this._xaxis,c[2][0]),h.call(this._yaxis,c[2][1]),f.call(this._xaxis,c[1][0]),h.call(this._yaxis,c[1][1]),f.call(this._xaxis,c[0][0]),h.call(this._yaxis,c[0][1])]]}}return e};b.jqplot.BezierCurveRenderer.prototype.draw=function(c,g,d){var e;c.save();if(g.length){if(this.showLine){c.save();var f=(d!=null)?d:{};c.fillStyle=f.fillStyle||this.color;c.beginPath();c.moveTo(g[0][0],g[0][1]);c.bezierCurveTo(g[1][0],g[1][1],g[1][2],g[1][3],g[1][4],g[1][5]);c.lineTo(g[2][0],g[2][1]);if(g[3].length==2){c.lineTo(g[3][0],g[3][1])}else{c.bezierCurveTo(g[3][0],g[3][1],g[3][2],g[3][3],g[3][4],g[3][5])}c.closePath();c.fill();c.restore()}}c.restore()};b.jqplot.BezierCurveRenderer.prototype.drawShadow=function(c,e,d){};b.jqplot.BezierAxisRenderer=function(){b.jqplot.LinearAxisRenderer.call(this)};b.jqplot.BezierAxisRenderer.prototype=new b.jqplot.LinearAxisRenderer();b.jqplot.BezierAxisRenderer.prototype.constructor=b.jqplot.BezierAxisRenderer;b.jqplot.BezierAxisRenderer.prototype.init=function(f){b.extend(true,this,f);var c=this._dataBounds;for(var g=0;gc.max||c.max==null){c.max=k[e][0]}}else{if(k[e][1]c.max||c.max==null){c.max=k[e][1]}}}}else{if(this.name=="xaxis"||this.name=="x2axis"){if(k[0][0]c.max||c.max==null){c.max=k[0][0]}for(var e=0;e<5;e+=2){if(k[1][e]c.max||c.max==null){c.max=k[1][e]}}}else{if(k[0][1]c.max||c.max==null){c.max=k[0][1]}for(var e=1;e<6;e+=2){if(k[1][e]c.max||c.max==null){c.max=k[1][e]}}}}}};function a(g,f,d){d=d||{};d.axesDefaults=b.extend(true,{pad:0},d.axesDefaults);d.legend=b.extend(true,{placement:"outside"},d.legend);var c=false;if(d.seriesDefaults.renderer==b.jqplot.BezierCurveRenderer){c=true}else{if(d.series){for(var e=0;e 1) { + this.breakOnNull = true; + var l = this.data.length; + var skip = parseInt(l/this.rendererOptions.groups, 10); + var count = 0; + for (var i=skip; i 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + newrgb[j] = parseInt(newrgb[j], 10); + } + ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); + } + return ret; + } $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options) { var i; - var opts = (options != undefined) ? options : {}; + // Ughhh, have to make a copy of options b/c it may be modified later. + var opts = $.extend({}, options); var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; var fill = (opts.fill != undefined) ? opts.fill : this.fill; @@ -178,16 +268,20 @@ var yaxis = this.yaxis; var xp = this._xaxis.series_u2p; var yp = this._yaxis.series_u2p; - var pointx, pointy, nvals, nseries, pos; + var pointx, pointy; + // clear out data colors. + this._dataColors = []; + this._barPoints = []; if (this.barWidth == null) { this.renderer.setBarWidth.call(this); } - var temp = this.renderer.calcSeriesNumbers.call(this); - nvals = temp[0]; - nseries = temp[1]; - pos = temp[2]; + var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); + var nvals = temp[0]; + var nseries = temp[1]; + var pos = temp[2]; + var points = []; if (this._stack) { this._barNudge = 0; @@ -203,12 +297,18 @@ negativeColor = opts.fillStyle; } var positiveColor = opts.fillStyle; + var base; + var xstart; + var ystart; if (this.barDirection == 'vertical') { for (var i=0; i 0 && i < this.gridData.length-1) { ystart = this.gridData[i-1][1]; } + else if (this.waterfall && i == 0 && i < this.gridData.length-1) { + if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { + ystart = this._yaxis.series_u2p(0); + } + else if (this._yaxis.min > 0) { + ystart = ctx.canvas.height; + } + else { + ystart = 0; + } + } + else if (this.waterfall && i == this.gridData.length - 1) { + if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { + ystart = this._yaxis.series_u2p(0); + } + else if (this._yaxis.min > 0) { + ystart = ctx.canvas.height; + } + else { + ystart = 0; + } + } else { ystart = ctx.canvas.height; } } if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) { - if (this.varyBarColor) { + if (this.varyBarColor && !this._stack) { if (this.useNegativeColors) { opts.fillStyle = negativeColors.next(); } @@ -240,32 +362,50 @@ } } else { - if (this.varyBarColor) { + if (this.varyBarColor && !this._stack) { opts.fillStyle = positiveColors.next(); } else { opts.fillStyle = positiveColor; } } - - points.push([base-this.barWidth/2, ystart]); - points.push([base-this.barWidth/2, gridData[i][1]]); - points.push([base+this.barWidth/2, gridData[i][1]]); - points.push([base+this.barWidth/2, ystart]); + + if (!this.fillToZero || this._plotData[i][1] >= 0) { + points.push([base-this.barWidth/2, ystart]); + points.push([base-this.barWidth/2, gridData[i][1]]); + points.push([base+this.barWidth/2, gridData[i][1]]); + points.push([base+this.barWidth/2, ystart]); + } + // for negative bars make sure points are always ordered clockwise + else { + points.push([base-this.barWidth/2, gridData[i][1]]); + points.push([base-this.barWidth/2, ystart]); + points.push([base+this.barWidth/2, ystart]); + points.push([base+this.barWidth/2, gridData[i][1]]); + } + this._barPoints.push(points); // now draw the shadows if not stacked. // for stacked plots, they are predrawn by drawShadow if (shadow && !this._stack) { - this.renderer.shadowRenderer.draw(ctx, points, opts); + var sopts = $.extend(true, {}, opts); + // need to get rid of fillStyle on shadow. + delete sopts.fillStyle; + this.renderer.shadowRenderer.draw(ctx, points, sopts); } + var clr = opts.fillStyle || this.color; + this._dataColors.push(clr); this.renderer.shapeRenderer.draw(ctx, points, opts); } } else if (this.barDirection == 'horizontal'){ for (var i=0; i 0 && i < this.gridData.length-1) { xstart = this.gridData[i-1][1]; } + else if (this.waterfall && i == 0 && i < this.gridData.length-1) { + if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { + xstart = this._xaxis.series_u2p(0); + } + else if (this._xaxis.min > 0) { + xstart = 0; + } + else { + xstart = ctx.canvas.width; + } + } + else if (this.waterfall && i == this.gridData.length - 1) { + if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { + xstart = this._xaxis.series_u2p(0); + } + else if (this._xaxis.min > 0) { + xstart = 0; + } + else { + xstart = ctx.canvas.width; + } + } else { xstart = 0; } } if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) { - if (this.varyBarColor) { + if (this.varyBarColor && !this._stack) { if (this.useNegativeColors) { opts.fillStyle = negativeColors.next(); } @@ -293,7 +455,7 @@ } } else { - if (this.varyBarColor) { + if (this.varyBarColor && !this._stack) { opts.fillStyle = positiveColors.next(); } else { @@ -302,19 +464,36 @@ } points.push([xstart, base+this.barWidth/2]); - points.push([gridData[i][0], base+this.barWidth/2]); - points.push([gridData[i][0], base-this.barWidth/2]); points.push([xstart, base-this.barWidth/2]); + points.push([gridData[i][0], base-this.barWidth/2]); + points.push([gridData[i][0], base+this.barWidth/2]); + this._barPoints.push(points); // now draw the shadows if not stacked. // for stacked plots, they are predrawn by drawShadow if (shadow && !this._stack) { - this.renderer.shadowRenderer.draw(ctx, points, opts); + var sopts = $.extend(true, {}, opts); + delete sopts.fillStyle; + this.renderer.shadowRenderer.draw(ctx, points, sopts); } + var clr = opts.fillStyle || this.color; + this._dataColors.push(clr); this.renderer.shapeRenderer.draw(ctx, points, opts); } } } - + + if (this.highlightColors.length == 0) { + this.highlightColors = computeHighlightColors(this._dataColors); + } + + else if (typeof(this.highlightColors) == 'string') { + var temp = this.highlightColors; + this.highlightColors = []; + for (var i=0; i0){this.data[d][j]+=this.data[d-1][j]}}this.data[this.data.length]=(j==1)?[this.data.length+1,e]:[e,this.data.length+1];this._data[this._data.length]=(j==1)?[this._data.length+1,e]:[e,this._data.length+1]}}b.jqplot.preSeriesInitHooks.push(a);b.jqplot.BarRenderer.prototype.calcSeriesNumbers=function(){var g=0;var h=0;var f=this[this._primaryAxis];var e,d,j;for(var c=0;c0&&u0&&u0){this.data[p][t]+=this.data[p-1][t]}}this.data[this.data.length]=(t==1)?[this.data.length+1,r]:[r,this.data.length+1];this._data[this._data.length]=(t==1)?[this._data.length+1,r]:[r,this._data.length+1]}if(this.rendererOptions.groups>1){this.breakOnNull=true;var m=this.data.length;var u=parseInt(m/this.rendererOptions.groups,10);var q=0;for(var p=u;p570)?m[o]*0.8:m[o]+0.3*(255-m[o]);m[o]=parseInt(m[o],10)}p.push("rgb("+m[0]+","+m[1]+","+m[2]+")")}return p}d.jqplot.BarRenderer.prototype.draw=function(D,J,p){var G;var z=d.extend({},p);var u=(z.shadow!=undefined)?z.shadow:this.shadow;var M=(z.showLine!=undefined)?z.showLine:this.showLine;var E=(z.fill!=undefined)?z.fill:this.fill;var o=this.xaxis;var H=this.yaxis;var x=this._xaxis.series_u2p;var I=this._yaxis.series_u2p;var C,B;this._dataColors=[];this._barPoints=[];if(this.barWidth==null){this.renderer.setBarWidth.call(this)}var L=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);var w=L[0];var v=L[1];var r=L[2];var F=[];if(this._stack){this._barNudge=0}else{this._barNudge=(-Math.abs(v/2-0.5)+r)*(this.barWidth+this.barPadding)}if(M){var t=new d.jqplot.ColorGenerator(this.negativeSeriesColors);var A=new d.jqplot.ColorGenerator(this.seriesColors);var K=t.get(this.index);if(!this.useNegativeColors){K=z.fillStyle}var s=z.fillStyle;var q;var N;var n;if(this.barDirection=="vertical"){for(var G=0;G0&&G=0){n=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){n=D.canvas.height}else{n=0}}}else{if(this.waterfall&&G==this.gridData.length-1){if(this._yaxis.min<=0&&this._yaxis.max>=0){n=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){n=D.canvas.height}else{n=0}}}else{n=D.canvas.height}}}}}if((this.fillToZero&&this._plotData[G][1]<0)||(this.waterfall&&this._data[G][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){z.fillStyle=t.next()}else{z.fillStyle=A.next()}}else{z.fillStyle=K}}else{if(this.varyBarColor&&!this._stack){z.fillStyle=A.next()}else{z.fillStyle=s}}if(!this.fillToZero||this._plotData[G][1]>=0){F.push([q-this.barWidth/2,n]);F.push([q-this.barWidth/2,J[G][1]]);F.push([q+this.barWidth/2,J[G][1]]);F.push([q+this.barWidth/2,n])}else{F.push([q-this.barWidth/2,J[G][1]]);F.push([q-this.barWidth/2,n]);F.push([q+this.barWidth/2,n]);F.push([q+this.barWidth/2,J[G][1]])}this._barPoints.push(F);if(u&&!this._stack){var y=d.extend(true,{},z);delete y.fillStyle;this.renderer.shadowRenderer.draw(D,F,y)}var m=z.fillStyle||this.color;this._dataColors.push(m);this.renderer.shapeRenderer.draw(D,F,z)}}else{if(this.barDirection=="horizontal"){for(var G=0;G0&&G=0){N=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){N=0}else{N=D.canvas.width}}}else{if(this.waterfall&&G==this.gridData.length-1){if(this._xaxis.min<=0&&this._xaxis.max>=0){N=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){N=0}else{N=D.canvas.width}}}else{N=0}}}}}if((this.fillToZero&&this._plotData[G][1]<0)||(this.waterfall&&this._data[G][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){z.fillStyle=t.next()}else{z.fillStyle=A.next()}}}else{if(this.varyBarColor&&!this._stack){z.fillStyle=A.next()}else{z.fillStyle=s}}F.push([N,q+this.barWidth/2]);F.push([N,q-this.barWidth/2]);F.push([J[G][0],q-this.barWidth/2]);F.push([J[G][0],q+this.barWidth/2]);this._barPoints.push(F);if(u&&!this._stack){var y=d.extend(true,{},z);delete y.fillStyle;this.renderer.shadowRenderer.draw(D,F,y)}var m=z.fillStyle||this.color;this._dataColors.push(m);this.renderer.shapeRenderer.draw(D,F,z)}}}}if(this.highlightColors.length==0){this.highlightColors=f(this._dataColors)}else{if(typeof(this.highlightColors)=="string"){var L=this.highlightColors;this.highlightColors=[];for(var G=0;G [[x1, y1, "label 1", {css}], [x2, y2, "label 2", {css}], ...] + * + * The label and css object are optional. If the label is ommitted, the + * box will collapse unless a css height and/or width is specified. + * + * The css object is an object specifying css properties + * such as: + * + * > {background:'#4f98a5', border:'3px solid gray', padding:'1px'} + * + * Note that css properties specified with the data point override defaults + * specified with the series. + * + */ + $.jqplot.BlockRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.BlockRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.BlockRenderer.prototype.constructor = $.jqplot.BlockRenderer; + + // called with scope of a series + $.jqplot.BlockRenderer.prototype.init = function(options) { + // Group: Properties + // + // prop: css + // default css styles that will be applied to all data blocks. + // these values will be overridden by css styles supplied with the + // individulal data points. + this.css = {padding:'2px', border:'1px solid #999', textAlign:'center'}; + // prop: escapeHtml + // true to escape html in the box label. + this.escapeHtml = false; + // prop: insertBreaks + // true to turn spaces in data block label into html breaks
. + this.insertBreaks = true; + // prop: varyBlockColors + // true to vary the color of each block in this series according to + // the seriesColors array. False to set each block to the color + // specified on this series. This has no effect if a css background color + // option is specified in the renderer css options. + this.varyBlockColors = false; + $.extend(true, this, options); + if (this.css.backgroundColor) { + this.color = this.css.backgroundColor; + } + else if (this.css.background) { + this.color = this.css.background; + } + else if (!this.varyBlockColors) { + this.css.background = this.color; + } + this.canvas = new $.jqplot.BlockCanvas(); + this.shadowCanvas = new $.jqplot.BlockCanvas(); + this.canvas._plotDimensions = this._plotDimensions; + this.shadowCanvas._plotDimensions = this._plotDimensions; + this._type = 'block'; + + // group: Methods + // + // Method: moveBlock + // Moves an individual block. More efficient than redrawing + // the whole series by calling plot.drawSeries(). + // Properties: + // idx - the 0 based index of the block or point in this series. + // x - the x coordinate in data units (value on x axis) to move the block to. + // y - the y coordinate in data units (value on the y axis) to move the block to. + // duration - optional parameter to create an animated movement. Can be a + // number (higher is slower animation) or 'fast', 'normal' or 'slow'. If not + // provided, the element is moved without any animation. + this.moveBlock = function (idx, x, y, duration) { + // update plotData, stackData, data and gridData + // x and y are in data coordinates. + var el = this.canvas._elem.children(':eq('+idx+')'); + this.data[idx][0] = x; + this.data[idx][1] = y; + this._plotData[idx][0] = x; + this._plotData[idx][1] = y; + this._stackData[idx][0] = x; + this._stackData[idx][1] = y; + this.gridData[idx][0] = this._xaxis.series_u2p(x); + this.gridData[idx][1] = this._yaxis.series_u2p(y); + var w = el.outerWidth(); + var h = el.outerHeight(); + var left = this.gridData[idx][0] - w/2 + 'px'; + var top = this.gridData[idx][1] - h/2 + 'px'; + if (duration) { + if (parseInt(duration, 10)) { + duration = parseInt(duration, 10); + } + el.animate({left:left, top:top}, duration); + } + else { + el.css({left:left, top:top}); + } + el = null; + }; + }; + + // called with scope of series + $.jqplot.BlockRenderer.prototype.draw = function (ctx, gd, options) { + if (this.plugins.pointLabels) { + this.plugins.pointLabels.show = false; + } + var i, el, d, gd, t, css, w, h, left, top; + var opts = (options != undefined) ? options : {}; + var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); + this.canvas._elem.empty(); + for (i=0; i'); + } + css = $.extend(true, {}, this.css, css); + // create a div + el = $('
'); + this.canvas._elem.append(el); + // set text + this.escapeHtml ? el.text(t) : el.html(t); + // style it + // remove styles we don't want overridden. + delete css.position; + delete css.marginRight; + delete css.marginLeft; + if (!css.background && !css.backgroundColor && !css.backgroundImage){ + css.background = colorGenerator.next(); + } + el.css(css); + w = el.outerWidth(); + h = el.outerHeight(); + left = gd[0] - w/2 + 'px'; + top = gd[1] - h/2 + 'px'; + el.css({left:left, top:top}); + el = null; + } + }; + + $.jqplot.BlockCanvas = function() { + $.jqplot.ElemContainer.call(this); + this._ctx; + }; + + $.jqplot.BlockCanvas.prototype = new $.jqplot.ElemContainer(); + $.jqplot.BlockCanvas.prototype.constructor = $.jqplot.BlockCanvas; + + $.jqplot.BlockCanvas.prototype.createElement = function(offsets, clss, plotDimensions) { + this._offsets = offsets; + var klass = 'jqplot-blockCanvas'; + if (clss != undefined) { + klass = clss; + } + var elem; + // if this canvas already has a dom element, don't make a new one. + if (this._elem) { + elem = this._elem.get(0); + } + else { + elem = document.createElement('div'); + } + // if new plotDimensions supplied, use them. + if (plotDimensions != undefined) { + this._plotDimensions = plotDimensions; + } + + var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px'; + var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px'; + this._elem = $(elem); + this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top }); + + this._elem.addClass(klass); + return this._elem; + }; + + $.jqplot.BlockCanvas.prototype.setContext = function() { + this._ctx = { + canvas:{ + width:0, + height:0 + }, + clearRect:function(){return null;} + }; + return this._ctx; + }; + +})(jQuery); + + \ No newline at end of file diff --git a/js/jquery/jqplot-plugins/jqplot.blockRenderer.min.js b/js/jquery/jqplot-plugins/jqplot.blockRenderer.min.js new file mode 100644 index 0000000000..62404280b9 --- /dev/null +++ b/js/jquery/jqplot-plugins/jqplot.blockRenderer.min.js @@ -0,0 +1,30 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.0b2_r792 + * + * Copyright (c) 2009-2011 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function(a){a.jqplot.BlockRenderer=function(){a.jqplot.LineRenderer.call(this)};a.jqplot.BlockRenderer.prototype=new a.jqplot.LineRenderer();a.jqplot.BlockRenderer.prototype.constructor=a.jqplot.BlockRenderer;a.jqplot.BlockRenderer.prototype.init=function(b){this.css={padding:"2px",border:"1px solid #999",textAlign:"center"};this.escapeHtml=false;this.insertBreaks=true;this.varyBlockColors=false;a.extend(true,this,b);if(this.css.backgroundColor){this.color=this.css.backgroundColor}else{if(this.css.background){this.color=this.css.background}else{if(!this.varyBlockColors){this.css.background=this.color}}}this.canvas=new a.jqplot.BlockCanvas();this.shadowCanvas=new a.jqplot.BlockCanvas();this.canvas._plotDimensions=this._plotDimensions;this.shadowCanvas._plotDimensions=this._plotDimensions;this._type="block";this.moveBlock=function(l,j,i,e){var c=this.canvas._elem.children(":eq("+l+")");this.data[l][0]=j;this.data[l][1]=i;this._plotData[l][0]=j;this._plotData[l][1]=i;this._stackData[l][0]=j;this._stackData[l][1]=i;this.gridData[l][0]=this._xaxis.series_u2p(j);this.gridData[l][1]=this._yaxis.series_u2p(i);var k=c.outerWidth();var f=c.outerHeight();var d=this.gridData[l][0]-k/2+"px";var g=this.gridData[l][1]-f/2+"px";if(e){if(parseInt(e,10)){e=parseInt(e,10)}c.animate({left:d,top:g},e)}else{c.css({left:d,top:g})}c=null}};a.jqplot.BlockRenderer.prototype.draw=function(q,o,r){if(this.plugins.pointLabels){this.plugins.pointLabels.show=false}var f,c,l,o,p,k,n,g,e,m;var b=(r!=undefined)?r:{};var j=new a.jqplot.ColorGenerator(this.seriesColors);this.canvas._elem.empty();for(f=0;f")}k=a.extend(true,{},this.css,k);c=a('
');this.canvas._elem.append(c);this.escapeHtml?c.text(p):c.html(p);delete k.position;delete k.marginRight;delete k.marginLeft;if(!k.background&&!k.backgroundColor&&!k.backgroundImage){k.background=j.next()}c.css(k);n=c.outerWidth();g=c.outerHeight();e=o[0]-n/2+"px";m=o[1]-g/2+"px";c.css({left:e,top:m});c=null}};a.jqplot.BlockCanvas=function(){a.jqplot.ElemContainer.call(this);this._ctx};a.jqplot.BlockCanvas.prototype=new a.jqplot.ElemContainer();a.jqplot.BlockCanvas.prototype.constructor=a.jqplot.BlockCanvas;a.jqplot.BlockCanvas.prototype.createElement=function(i,e,c){this._offsets=i;var b="jqplot-blockCanvas";if(e!=undefined){b=e}var g;if(this._elem){g=this._elem.get(0)}else{g=document.createElement("div")}if(c!=undefined){this._plotDimensions=c}var d=this._plotDimensions.width-this._offsets.left-this._offsets.right+"px";var f=this._plotDimensions.height-this._offsets.top-this._offsets.bottom+"px";this._elem=a(g);this._elem.css({position:"absolute",width:d,height:f,left:this._offsets.left,top:this._offsets.top});this._elem.addClass(b);return this._elem};a.jqplot.BlockCanvas.prototype.setContext=function(){this._ctx={canvas:{width:0,height:0},clearRect:function(){return null}};return this._ctx}})(jQuery); \ No newline at end of file diff --git a/js/jquery/jqplot-plugins/jqplot.bubbleRenderer.js b/js/jquery/jqplot-plugins/jqplot.bubbleRenderer.js new file mode 100644 index 0000000000..2d70ace224 --- /dev/null +++ b/js/jquery/jqplot-plugins/jqplot.bubbleRenderer.js @@ -0,0 +1,754 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.0b2_r792 + * + * Copyright (c) 2009-2011 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + var arrayMax = function( array ){ + return Math.max.apply( Math, array ); + }; + var arrayMin = function( array ){ + return Math.min.apply( Math, array ); + }; + + /** + * Class: $.jqplot.BubbleRenderer + * Plugin renderer to draw a bubble chart. A Bubble chart has data points displayed as + * colored circles with an optional text label inside. To use + * the bubble renderer, you must include the bubble renderer like: + * + * > + * + * Data must be supplied in + * the form: + * + * > [[x1, y1, r1,