[MERGE] Merged with trunk
bzr revid: fme@openerp.com-20110801092617-f4vcc8dhx31n5ot3
This commit is contained in:
commit
a291c46b27
|
@ -3,4 +3,38 @@
|
|||
"version" : "2.0",
|
||||
"depends" : [],
|
||||
'active': True,
|
||||
'js' : [
|
||||
"static/lib/datejs/date-en-US.js",
|
||||
"static/lib/jquery/jquery-1.5.2.js",
|
||||
"static/lib/jquery.ba-bbq/jquery.ba-bbq.js",
|
||||
"static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js",
|
||||
"static/lib/jquery.superfish/js/hoverIntent.js",
|
||||
"static/lib/jquery.superfish/js/superfish.js",
|
||||
"static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js",
|
||||
"static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js",
|
||||
"static/lib/jquery.ui.notify/js/jquery.notify.js",
|
||||
"static/lib/json/json2.js",
|
||||
"static/lib/qweb/qweb2.js",
|
||||
"static/lib/underscore/underscore.js",
|
||||
"static/lib/underscore/underscore.string.js",
|
||||
"static/src/js/boot.js",
|
||||
"static/src/js/core.js",
|
||||
"static/src/js/dates.js",
|
||||
"static/src/js/chrome.js",
|
||||
"static/src/js/views.js",
|
||||
"static/src/js/data.js",
|
||||
"static/src/js/data_export.js",
|
||||
"static/src/js/form.js",
|
||||
"static/src/js/list.js",
|
||||
"static/src/js/list-editable.js",
|
||||
"static/src/js/search.js",
|
||||
"static/src/js/view_tree.js",
|
||||
],
|
||||
'css' : [
|
||||
"static/lib/jquery.superfish/css/superfish.css",
|
||||
"static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css",
|
||||
"static/lib/jquery.ui.notify/css/ui.notify.css",
|
||||
"static/src/css/base.css",
|
||||
"static/src/css/data_export.css",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import glob, os
|
||||
import pprint
|
||||
import base64, glob, os, re
|
||||
from xml.etree import ElementTree
|
||||
from cStringIO import StringIO
|
||||
|
||||
|
@ -12,6 +10,8 @@ import openerpweb.ast
|
|||
import openerpweb.nonliterals
|
||||
|
||||
import cherrypy
|
||||
import csv
|
||||
import xml.dom.minidom
|
||||
|
||||
# Should move to openerpweb.Xml2Json
|
||||
class Xml2Json:
|
||||
|
@ -56,40 +56,116 @@ class Xml2Json:
|
|||
# OpenERP Web base Controllers
|
||||
#----------------------------------------------------------
|
||||
|
||||
def manifest_glob(addons, key):
|
||||
files = []
|
||||
for addon in addons:
|
||||
globlist = openerpweb.addons_manifest.get(addon, {}).get(key, [])
|
||||
print globlist
|
||||
for pattern in globlist:
|
||||
for path in glob.glob(os.path.join(openerpweb.path_addons, addon, pattern)):
|
||||
files.append(path[len(openerpweb.path_addons):])
|
||||
return files
|
||||
|
||||
def concat_files(file_list):
|
||||
""" Concatenate file content
|
||||
return (concat,timestamp)
|
||||
concat: concatenation of file content
|
||||
timestamp: max(os.path.getmtime of file_list)
|
||||
"""
|
||||
root = openerpweb.path_root
|
||||
files_content = []
|
||||
files_timestamp = 0
|
||||
for i in file_list:
|
||||
fname = os.path.join(root, i)
|
||||
ftime = os.path.getmtime(fname)
|
||||
if ftime > files_timestamp:
|
||||
files_timestamp = ftime
|
||||
files_content = open(fname).read()
|
||||
files_concat = "".join(files_content)
|
||||
return files_concat
|
||||
|
||||
class WebClient(openerpweb.Controller):
|
||||
_cp_path = "/base/webclient"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def csslist(self, req, mods='base'):
|
||||
return manifest_glob(mods.split(','), 'css')
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def jslist(self, req, mods='base'):
|
||||
return manifest_glob(mods.split(','), 'js')
|
||||
|
||||
@openerpweb.httprequest
|
||||
def css(self, req, mods='base'):
|
||||
cherrypy.response.headers['Content-Type'] = 'text/css'
|
||||
files = manifest_glob(mods.split(','), 'css')
|
||||
concat = concat_files(files)[0]
|
||||
# TODO request set the Date of last modif and Etag
|
||||
return concat
|
||||
|
||||
@openerpweb.httprequest
|
||||
def js(self, req, mods='base'):
|
||||
cherrypy.response.headers['Content-Type'] = 'application/javascript'
|
||||
files = manifest_glob(mods.split(','), 'js')
|
||||
concat = concat_files(files)[0]
|
||||
# TODO request set the Date of last modif and Etag
|
||||
return concat
|
||||
|
||||
@openerpweb.httprequest
|
||||
def home(self, req):
|
||||
template ="""<!DOCTYPE html>
|
||||
<html style="height: 100%%">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP</title>
|
||||
%s
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
QWeb = new QWeb2.Engine();
|
||||
openerp.init().base.webclient("oe");
|
||||
});
|
||||
</script>
|
||||
<link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
%s
|
||||
<!--[if lte IE 7]>
|
||||
<link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body id="oe" class="openerp"></body>
|
||||
</html>
|
||||
""".replace('\n'+' '*8,'\n')
|
||||
|
||||
# script tags
|
||||
jslist = ['/base/webclient/js']
|
||||
if 1: # debug == 1
|
||||
jslist = manifest_glob(['base'], 'js')
|
||||
js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
|
||||
|
||||
# css tags
|
||||
csslist = ['/base/webclient/css']
|
||||
if 1: # debug == 1
|
||||
csslist = manifest_glob(['base'], 'css')
|
||||
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
|
||||
r = template % (js, css)
|
||||
return r
|
||||
|
||||
class Database(openerpweb.Controller):
|
||||
_cp_path = "/base/database"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get_databases_list(self, req):
|
||||
proxy = req.session.proxy("db")
|
||||
dbs = proxy.list()
|
||||
h = req.httprequest.headers['Host'].split(':')[0]
|
||||
d = h.split('.')[0]
|
||||
r = cherrypy.config['openerp.dbfilter'].replace('%h',h).replace('%d',d)
|
||||
print "h,d",h,d,r
|
||||
dbs = [i for i in dbs if re.match(r,i)]
|
||||
return {"db_list": dbs}
|
||||
|
||||
class Session(openerpweb.Controller):
|
||||
_cp_path = "/base/session"
|
||||
|
||||
def manifest_glob(self, addons, key):
|
||||
files = []
|
||||
for addon in addons:
|
||||
globlist = openerpweb.addons_manifest.get(addon, {}).get(key, [])
|
||||
|
||||
files.extend([
|
||||
resource_path[len(openerpweb.path_addons):]
|
||||
for pattern in globlist
|
||||
for resource_path in glob.glob(os.path.join(
|
||||
openerpweb.path_addons, addon, pattern))
|
||||
])
|
||||
return files
|
||||
|
||||
def concat_files(self, file_list):
|
||||
""" Concatenate file content
|
||||
return (concat,timestamp)
|
||||
concat: concatenation of file content
|
||||
timestamp: max(os.path.getmtime of file_list)
|
||||
"""
|
||||
root = openerpweb.path_root
|
||||
files_content = []
|
||||
files_timestamp = 0
|
||||
for i in file_list:
|
||||
fname = os.path.join(root, i)
|
||||
ftime = os.path.getmtime(fname)
|
||||
if ftime > files_timestamp:
|
||||
files_timestamp = ftime
|
||||
files_content = open(fname).read()
|
||||
files_concat = "".join(files_content)
|
||||
return files_concat
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def login(self, req, db, login, password):
|
||||
req.session.login(db, login, password)
|
||||
|
@ -104,40 +180,14 @@ class Session(openerpweb.Controller):
|
|||
return req.session.model('ir.ui.view_sc').get_sc(req.session._uid, "ir.ui.menu",
|
||||
req.session.eval_context(req.context))
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get_databases_list(self, req):
|
||||
proxy = req.session.proxy("db")
|
||||
dbs = proxy.list()
|
||||
|
||||
return {"db_list": dbs}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def modules(self, req):
|
||||
return {"modules": [name
|
||||
for name, manifest in openerpweb.addons_manifest.iteritems()
|
||||
if manifest.get('active', True)]}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def csslist(self, req, mods='base'):
|
||||
return {'files': self.manifest_glob(mods.split(','), 'css')}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def jslist(self, req, mods='base'):
|
||||
return {'files': self.manifest_glob(mods.split(','), 'js')}
|
||||
|
||||
def css(self, req, mods='base,base_hello'):
|
||||
files = self.manifest_glob(mods.split(','), 'css')
|
||||
concat = self.concat_files(files)[0]
|
||||
# TODO request set the Date of last modif and Etag
|
||||
return concat
|
||||
css.exposed = True
|
||||
|
||||
def js(self, req, mods='base,base_hello'):
|
||||
files = self.manifest_glob(mods.split(','), 'js')
|
||||
concat = self.concat_files(files)[0]
|
||||
# TODO request set the Date of last modif and Etag
|
||||
return concat
|
||||
js.exposed = True
|
||||
# TODO query server for installed web modules
|
||||
mods = []
|
||||
for name, manifest in openerpweb.addons_manifest.items():
|
||||
if name != 'base' and manifest.get('active', True):
|
||||
mods.append(name)
|
||||
return mods
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def eval_domain_and_context(self, req, contexts, domains,
|
||||
|
@ -174,7 +224,7 @@ class Session(openerpweb.Controller):
|
|||
context, domain = eval_context_and_domain(req.session,
|
||||
openerpweb.nonliterals.CompoundContext(*(contexts or [])),
|
||||
openerpweb.nonliterals.CompoundDomain(*(domains or [])))
|
||||
|
||||
|
||||
group_by_sequence = []
|
||||
for candidate in (group_by_seq or []):
|
||||
ctx = req.session.eval_context(candidate, context)
|
||||
|
@ -185,7 +235,7 @@ class Session(openerpweb.Controller):
|
|||
group_by_sequence.append(group_by)
|
||||
else:
|
||||
group_by_sequence.extend(group_by)
|
||||
|
||||
|
||||
return {
|
||||
'context': context,
|
||||
'domain': domain,
|
||||
|
@ -198,7 +248,7 @@ class Session(openerpweb.Controller):
|
|||
This method store an action object in the session object and returns an integer
|
||||
identifying that action. The method get_session_action() can be used to get
|
||||
back the action.
|
||||
|
||||
|
||||
:param the_action: The action to save in the session.
|
||||
:type the_action: anything
|
||||
:return: A key identifying the saved action.
|
||||
|
@ -221,7 +271,7 @@ class Session(openerpweb.Controller):
|
|||
"""
|
||||
Gets back a previously saved action. This method can return None if the action
|
||||
was saved since too much time (this case should be handled in a smart way).
|
||||
|
||||
|
||||
:param key: The key given by save_session_action()
|
||||
:type key: integer
|
||||
:return: The saved action or None.
|
||||
|
@ -231,24 +281,24 @@ class Session(openerpweb.Controller):
|
|||
if not saved_actions:
|
||||
return None
|
||||
return saved_actions["actions"].get(key)
|
||||
|
||||
|
||||
def eval_context_and_domain(session, context, domain=None):
|
||||
e_context = session.eval_context(context)
|
||||
# should we give the evaluated context as an evaluation context to the domain?
|
||||
e_domain = session.eval_domain(domain or [])
|
||||
|
||||
return e_context, e_domain
|
||||
|
||||
|
||||
def load_actions_from_ir_values(req, key, key2, models, meta, context):
|
||||
Values = req.session.model('ir.values')
|
||||
actions = Values.get(key, key2, models, meta, context)
|
||||
|
||||
for _, _, action in actions:
|
||||
clean_action(action, req.session)
|
||||
|
||||
return actions
|
||||
return [(id, name, clean_action(action, req.session))
|
||||
for id, name, action in actions]
|
||||
|
||||
def clean_action(action, session):
|
||||
if action['type'] != 'ir.actions.act_window':
|
||||
return action
|
||||
# values come from the server, we can just eval them
|
||||
if isinstance(action.get('context', None), basestring):
|
||||
action['context'] = eval(
|
||||
|
@ -259,12 +309,49 @@ def clean_action(action, session):
|
|||
action['domain'] = eval(
|
||||
action['domain'],
|
||||
session.evaluation_context(
|
||||
action['context'])) or []
|
||||
if not action.has_key('flags'):
|
||||
action.get('context', {}))) or []
|
||||
if 'flags' not in action:
|
||||
# Set empty flags dictionary for web client.
|
||||
action['flags'] = dict()
|
||||
return fix_view_modes(action)
|
||||
|
||||
def generate_views(action):
|
||||
"""
|
||||
While the server generates a sequence called "views" computing dependencies
|
||||
between a bunch of stuff for views coming directly from the database
|
||||
(the ``ir.actions.act_window model``), it's also possible for e.g. buttons
|
||||
to return custom view dictionaries generated on the fly.
|
||||
|
||||
In that case, there is no ``views`` key available on the action.
|
||||
|
||||
Since the web client relies on ``action['views']``, generate it here from
|
||||
``view_mode`` and ``view_id``.
|
||||
|
||||
Currently handles two different cases:
|
||||
|
||||
* no view_id, multiple view_mode
|
||||
* single view_id, single view_mode
|
||||
|
||||
:param dict action: action descriptor dictionary to generate a views key for
|
||||
"""
|
||||
view_id = action.get('view_id', False)
|
||||
if isinstance(view_id, (list, tuple)):
|
||||
view_id = view_id[0]
|
||||
|
||||
# providing at least one view mode is a requirement, not an option
|
||||
view_modes = action['view_mode'].split(',')
|
||||
|
||||
if len(view_modes) > 1:
|
||||
if view_id:
|
||||
raise ValueError('Non-db action dictionaries should provide '
|
||||
'either multiple view modes or a single view '
|
||||
'mode and an optional view id.\n\n Got view '
|
||||
'modes %r and view id %r for action %r' % (
|
||||
view_modes, view_id, action))
|
||||
action['views'] = [(False, mode) for mode in view_modes]
|
||||
return
|
||||
action['views'] = [(view_id, view_modes[0])]
|
||||
|
||||
def fix_view_modes(action):
|
||||
""" For historical reasons, OpenERP has weird dealings in relation to
|
||||
view_mode and the view_type attribute (on window actions):
|
||||
|
@ -283,18 +370,17 @@ def fix_view_modes(action):
|
|||
:param dict action: an action descriptor
|
||||
:returns: nothing, the action is modified in place
|
||||
"""
|
||||
if action.pop('view_type') != 'form':
|
||||
return
|
||||
if 'views' not in action:
|
||||
generate_views(action)
|
||||
|
||||
if action.pop('view_type') != 'form':
|
||||
return action
|
||||
|
||||
action['views'] = [
|
||||
[id, mode if mode != 'tree' else 'list']
|
||||
for id, mode in action['views']
|
||||
]
|
||||
|
||||
if action.has_key('view_mode'):
|
||||
action['view_mode'] = ','.join(
|
||||
mode if mode != 'tree' else 'list'
|
||||
for mode in action['view_mode'].split(','))
|
||||
if action.has_key('views'):
|
||||
action['views'] = [
|
||||
[id, mode if mode != 'tree' else 'list']
|
||||
for id, mode in action['views']
|
||||
]
|
||||
return action
|
||||
|
||||
class Menu(openerpweb.Controller):
|
||||
|
@ -320,7 +406,7 @@ class Menu(openerpweb.Controller):
|
|||
menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context)
|
||||
menu_root = {'id': False, 'name': 'root', 'parent_id': [-1, '']}
|
||||
menu_items.append(menu_root)
|
||||
|
||||
|
||||
# make a tree using parent_id
|
||||
menu_items_map = dict((menu_item["id"], menu_item) for menu_item in menu_items)
|
||||
for menu_item in menu_items:
|
||||
|
@ -355,9 +441,10 @@ class DataSet(openerpweb.Controller):
|
|||
req.session.eval_context(req.context))}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, context=None, sort=None):
|
||||
return self.do_search_read(request, model, fields, offset, limit, domain, context, sort)
|
||||
def do_search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, context=None, sort=None):
|
||||
def search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, sort=None):
|
||||
return self.do_search_read(request, model, fields, offset, limit, domain, sort)
|
||||
def do_search_read(self, request, model, fields=False, offset=0, limit=False, domain=None
|
||||
, sort=None):
|
||||
""" Performs a search() followed by a read() (if needed) using the
|
||||
provided search criteria
|
||||
|
||||
|
@ -370,22 +457,33 @@ class DataSet(openerpweb.Controller):
|
|||
:param int limit: the maximum number of records to return
|
||||
:param list domain: the search domain for the query
|
||||
:param list sort: sorting directives
|
||||
:returns: a list of result records
|
||||
:returns: A structure (dict) with two keys: ids (all the ids matching
|
||||
the (domain, context) pair) and records (paginated records
|
||||
matching fields selection set)
|
||||
:rtype: list
|
||||
"""
|
||||
Model = request.session.model(model)
|
||||
context, domain = eval_context_and_domain(request.session, request.context, domain)
|
||||
|
||||
ids = Model.search(domain, offset or 0, limit or False,
|
||||
sort or False, context)
|
||||
context, domain = eval_context_and_domain(
|
||||
request.session, request.context, domain)
|
||||
|
||||
ids = Model.search(domain, 0, False, sort or False, context)
|
||||
# need to fill the dataset with all ids for the (domain, context) pair,
|
||||
# so search un-paginated and paginate manually before reading
|
||||
paginated_ids = ids[offset:(offset + limit if limit else None)]
|
||||
if fields and fields == ['id']:
|
||||
# shortcut read if we only want the ids
|
||||
return map(lambda id: {'id': id}, ids)
|
||||
return {
|
||||
'ids': ids,
|
||||
'records': map(lambda id: {'id': id}, paginated_ids)
|
||||
}
|
||||
|
||||
records = Model.read(paginated_ids, fields or False, context)
|
||||
records.sort(key=lambda obj: ids.index(obj['id']))
|
||||
return {
|
||||
'ids': ids,
|
||||
'records': records
|
||||
}
|
||||
|
||||
reads = Model.read(ids, fields or False, context)
|
||||
reads.sort(key=lambda obj: ids.index(obj['id']))
|
||||
return reads
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get(self, request, model, ids, fields=False):
|
||||
|
@ -415,7 +513,7 @@ class DataSet(openerpweb.Controller):
|
|||
record_map = dict((record['id'], record) for record in records)
|
||||
|
||||
return [record_map[id] for id in ids if record_map.get(id)]
|
||||
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req, model, id, fields):
|
||||
m = req.session.model(model)
|
||||
|
@ -455,14 +553,14 @@ class DataSet(openerpweb.Controller):
|
|||
|
||||
@openerpweb.jsonrequest
|
||||
def call(self, req, model, method, args, domain_id=None, context_id=None):
|
||||
return {'result': self.call_common(req, model, method, args, domain_id, context_id)}
|
||||
return self.call_common(req, model, method, args, domain_id, context_id)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def call_button(self, req, model, method, args, domain_id=None, context_id=None):
|
||||
action = self.call_common(req, model, method, args, domain_id, context_id)
|
||||
if isinstance(action, dict) and action.get('type') != '':
|
||||
clean_action(action, req.session)
|
||||
return {'result': action}
|
||||
return {'result': clean_action(action, req.session)}
|
||||
return {'result': False}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def exec_workflow(self, req, model, id, signal):
|
||||
|
@ -471,20 +569,19 @@ class DataSet(openerpweb.Controller):
|
|||
|
||||
@openerpweb.jsonrequest
|
||||
def default_get(self, req, model, fields):
|
||||
m = req.session.model(model)
|
||||
r = m.default_get(fields, req.session.eval_context(req.context))
|
||||
return {'result': r}
|
||||
Model = req.session.model(model)
|
||||
return Model.default_get(fields, req.session.eval_context(req.context))
|
||||
|
||||
class DataGroup(openerpweb.Controller):
|
||||
_cp_path = "/base/group"
|
||||
@openerpweb.jsonrequest
|
||||
def read(self, request, model, group_by_fields, domain=None):
|
||||
def read(self, request, model, fields, group_by_fields, domain=None, sort=None):
|
||||
Model = request.session.model(model)
|
||||
context, domain = eval_context_and_domain(request.session, request.context, domain)
|
||||
|
||||
return Model.read_group(
|
||||
domain or [], False, group_by_fields, 0, False,
|
||||
dict(context, group_by=group_by_fields))
|
||||
domain or [], fields, group_by_fields, 0, False,
|
||||
dict(context, group_by=group_by_fields), sort or False)
|
||||
|
||||
class View(openerpweb.Controller):
|
||||
_cp_path = "/base/view"
|
||||
|
@ -497,18 +594,35 @@ class View(openerpweb.Controller):
|
|||
# todo fme?: check that we should pass the evaluated context here
|
||||
self.process_view(request.session, fvg, context, transform)
|
||||
return fvg
|
||||
|
||||
|
||||
def process_view(self, session, fvg, context, transform):
|
||||
# depending on how it feels, xmlrpclib.ServerProxy can translate
|
||||
# XML-RPC strings to ``str`` or ``unicode``. ElementTree does not
|
||||
# enjoy unicode strings which can not be trivially converted to
|
||||
# strings, and it blows up during parsing.
|
||||
|
||||
# So ensure we fix this retardation by converting view xml back to
|
||||
# bit strings.
|
||||
if isinstance(fvg['arch'], unicode):
|
||||
arch = fvg['arch'].encode('utf-8')
|
||||
else:
|
||||
arch = fvg['arch']
|
||||
|
||||
if transform:
|
||||
evaluation_context = session.evaluation_context(context or {})
|
||||
xml = self.transform_view(fvg['arch'], session, evaluation_context)
|
||||
xml = self.transform_view(arch, session, evaluation_context)
|
||||
else:
|
||||
xml = ElementTree.fromstring(fvg['arch'])
|
||||
xml = ElementTree.fromstring(arch)
|
||||
fvg['arch'] = Xml2Json.convert_element(xml)
|
||||
for field in fvg['fields'].values():
|
||||
if field.has_key('views') and field['views']:
|
||||
for view in field["views"].values():
|
||||
|
||||
for field in fvg['fields'].itervalues():
|
||||
if field.get('views'):
|
||||
for view in field["views"].itervalues():
|
||||
self.process_view(session, view, None, transform)
|
||||
if field.get('domain'):
|
||||
field["domain"] = self.parse_domain(field["domain"], session)
|
||||
if field.get('context'):
|
||||
field["context"] = self.parse_context(field["context"], session)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def add_custom(self, request, view_id, arch):
|
||||
|
@ -534,36 +648,6 @@ class View(openerpweb.Controller):
|
|||
return {'result': True}
|
||||
return {'result': False}
|
||||
|
||||
def normalize_attrs(self, elem, context):
|
||||
""" Normalize @attrs, @invisible, @required, @readonly and @states, so
|
||||
the client only has to deal with @attrs.
|
||||
|
||||
See `the discoveries pad <http://pad.openerp.com/discoveries>`_ for
|
||||
the rationale.
|
||||
|
||||
:param elem: the current view node (Python object)
|
||||
:type elem: xml.etree.ElementTree.Element
|
||||
:param dict context: evaluation context
|
||||
"""
|
||||
# If @attrs is normalized in json by server, the eval should be replaced by simplejson.loads
|
||||
attrs = openerpweb.ast.literal_eval(elem.get('attrs', '{}'))
|
||||
if 'states' in elem.attrib:
|
||||
attrs.setdefault('invisible', [])\
|
||||
.append(('state', 'not in', elem.attrib.pop('states').split(',')))
|
||||
if attrs:
|
||||
elem.set('attrs', simplejson.dumps(attrs))
|
||||
for a in ['invisible', 'readonly', 'required']:
|
||||
if a in elem.attrib:
|
||||
# In the XML we trust
|
||||
avalue = bool(eval(elem.get(a, 'False'),
|
||||
{'context': context or {}}))
|
||||
if not avalue:
|
||||
del elem.attrib[a]
|
||||
else:
|
||||
elem.attrib[a] = '1'
|
||||
if a == 'invisible' and 'attrs' in elem.attrib:
|
||||
del elem.attrib['attrs']
|
||||
|
||||
def transform_view(self, view_string, session, context=None):
|
||||
# transform nodes on the fly via iterparse, instead of
|
||||
# doing it statically on the parsing result
|
||||
|
@ -573,31 +657,41 @@ class View(openerpweb.Controller):
|
|||
if event == "start":
|
||||
if root is None:
|
||||
root = elem
|
||||
self.normalize_attrs(elem, context)
|
||||
self.parse_domains_and_contexts(elem, session)
|
||||
return root
|
||||
|
||||
def parse_domain(self, elem, attr_name, session):
|
||||
""" Parses an attribute of the provided name as a domain, transforms it
|
||||
def parse_domain(self, domain, session):
|
||||
""" Parses an arbitrary string containing a domain, transforms it
|
||||
to either a literal domain or a :class:`openerpweb.nonliterals.Domain`
|
||||
|
||||
:param elem: the node being parsed
|
||||
:type param: xml.etree.ElementTree.Element
|
||||
:param str attr_name: the name of the attribute which should be parsed
|
||||
:param domain: the domain to parse, if the domain is not a string it is assumed to
|
||||
be a literal domain and is returned as-is
|
||||
:param session: Current OpenERP session
|
||||
:type session: openerpweb.openerpweb.OpenERPSession
|
||||
"""
|
||||
domain = elem.get(attr_name, '').strip()
|
||||
if domain:
|
||||
try:
|
||||
elem.set(
|
||||
attr_name,
|
||||
openerpweb.ast.literal_eval(
|
||||
domain))
|
||||
except ValueError:
|
||||
# not a literal
|
||||
elem.set(attr_name,
|
||||
openerpweb.nonliterals.Domain(session, domain))
|
||||
if not isinstance(domain, (str, unicode)):
|
||||
return domain
|
||||
try:
|
||||
return openerpweb.ast.literal_eval(domain)
|
||||
except ValueError:
|
||||
# not a literal
|
||||
return openerpweb.nonliterals.Domain(session, domain)
|
||||
|
||||
def parse_context(self, context, session):
|
||||
""" Parses an arbitrary string containing a context, transforms it
|
||||
to either a literal context or a :class:`openerpweb.nonliterals.Context`
|
||||
|
||||
:param context: the context to parse, if the context is not a string it is assumed to
|
||||
be a literal domain and is returned as-is
|
||||
:param session: Current OpenERP session
|
||||
:type session: openerpweb.openerpweb.OpenERPSession
|
||||
"""
|
||||
if not isinstance(context, (str, unicode)):
|
||||
return context
|
||||
try:
|
||||
return openerpweb.ast.literal_eval(context)
|
||||
except ValueError:
|
||||
return openerpweb.nonliterals.Context(session, context)
|
||||
|
||||
def parse_domains_and_contexts(self, elem, session):
|
||||
""" Converts domains and contexts from the view into Python objects,
|
||||
|
@ -610,17 +704,14 @@ class View(openerpweb.Controller):
|
|||
non-literal objects
|
||||
:type session: openerpweb.openerpweb.OpenERPSession
|
||||
"""
|
||||
self.parse_domain(elem, 'domain', session)
|
||||
self.parse_domain(elem, 'filter_domain', session)
|
||||
context_string = elem.get('context', '').strip()
|
||||
if context_string:
|
||||
try:
|
||||
elem.set('context',
|
||||
openerpweb.ast.literal_eval(context_string))
|
||||
except ValueError:
|
||||
elem.set('context',
|
||||
openerpweb.nonliterals.Context(
|
||||
session, context_string))
|
||||
for el in ['domain', 'filter_domain']:
|
||||
domain = elem.get(el, '').strip()
|
||||
if domain:
|
||||
elem.set(el, self.parse_domain(domain, session))
|
||||
for el in ['context', 'default_get']:
|
||||
context_string = elem.get(el, '').strip()
|
||||
if context_string:
|
||||
elem.set(el, self.parse_context(context_string, session))
|
||||
|
||||
class FormView(View):
|
||||
_cp_path = "/base/formview"
|
||||
|
@ -668,7 +759,41 @@ class SearchView(View):
|
|||
def fields_get(self, req, model):
|
||||
Model = req.session.model(model)
|
||||
fields = Model.fields_get(False, req.session.eval_context(req.context))
|
||||
for field in fields.values():
|
||||
# shouldn't convert the views too?
|
||||
if field.get('domain'):
|
||||
field["domain"] = self.parse_domain(field["domain"], req.session)
|
||||
if field.get('context'):
|
||||
field["context"] = self.parse_domain(field["context"], req.session)
|
||||
return {'fields': fields}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get_filters(self, req, model):
|
||||
Model = req.session.model("ir.filters")
|
||||
filters = Model.get_filters(model)
|
||||
for filter in filters:
|
||||
filter["context"] = req.session.eval_context(self.parse_context(filter["context"], req.session))
|
||||
filter["domain"] = req.session.eval_domain(self.parse_domain(filter["domain"], req.session))
|
||||
return filters
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def save_filter(self, req, model, name, context_to_save, domain):
|
||||
Model = req.session.model("ir.filters")
|
||||
ctx = openerpweb.nonliterals.CompoundContext(context_to_save)
|
||||
ctx.session = req.session
|
||||
ctx = ctx.evaluate()
|
||||
domain = openerpweb.nonliterals.CompoundDomain(domain)
|
||||
domain.session = req.session
|
||||
domain = domain.evaluate()
|
||||
uid = req.session._uid
|
||||
context = req.session.eval_context(req.context)
|
||||
to_return = Model.create_or_replace({"context": ctx,
|
||||
"domain": domain,
|
||||
"model_id": model,
|
||||
"name": name,
|
||||
"user_id": uid
|
||||
}, context)
|
||||
return to_return
|
||||
|
||||
class Binary(openerpweb.Controller):
|
||||
_cp_path = "/base/binary"
|
||||
|
@ -774,3 +899,235 @@ class Action(openerpweb.Controller):
|
|||
if action:
|
||||
value = clean_action(action[0], req.session)
|
||||
return {'result': value}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def run(self, req, action_id):
|
||||
return clean_action(req.session.model('ir.actions.server').run(
|
||||
[action_id], req.session.eval_context(req.context)), req.session)
|
||||
|
||||
def export_csv(fields, result):
|
||||
import StringIO
|
||||
fp = StringIO.StringIO()
|
||||
writer = csv.writer(fp, quoting=csv.QUOTE_ALL)
|
||||
|
||||
writer.writerow(fields)
|
||||
|
||||
for data in result:
|
||||
row = []
|
||||
for d in data:
|
||||
if isinstance(d, basestring):
|
||||
d = d.replace('\n',' ').replace('\t',' ')
|
||||
try:
|
||||
d = d.encode('utf-8')
|
||||
except:
|
||||
pass
|
||||
if d is False: d = None
|
||||
row.append(d)
|
||||
writer.writerow(row)
|
||||
|
||||
fp.seek(0)
|
||||
data = fp.read()
|
||||
fp.close()
|
||||
return data
|
||||
|
||||
def export_xls(fieldnames, table):
|
||||
import StringIO
|
||||
try:
|
||||
import xlwt
|
||||
except ImportError:
|
||||
common.error(_('Import Error.'), _('Please install xlwt library to export to MS Excel.'))
|
||||
|
||||
workbook = xlwt.Workbook()
|
||||
worksheet = workbook.add_sheet('Sheet 1')
|
||||
|
||||
for i, fieldname in enumerate(fieldnames):
|
||||
worksheet.write(0, i, str(fieldname))
|
||||
worksheet.col(i).width = 8000 # around 220 pixels
|
||||
|
||||
style = xlwt.easyxf('align: wrap yes')
|
||||
|
||||
for row_index, row in enumerate(table):
|
||||
for cell_index, cell_value in enumerate(row):
|
||||
cell_value = str(cell_value)
|
||||
cell_value = re.sub("\r", " ", cell_value)
|
||||
worksheet.write(row_index + 1, cell_index, cell_value, style)
|
||||
|
||||
|
||||
fp = StringIO.StringIO()
|
||||
workbook.save(fp)
|
||||
fp.seek(0)
|
||||
data = fp.read()
|
||||
fp.close()
|
||||
#return data.decode('ISO-8859-1')
|
||||
return unicode(data, 'utf-8', 'replace')
|
||||
|
||||
def node_attributes(node):
|
||||
attrs = node.attributes
|
||||
|
||||
if not attrs:
|
||||
return {}
|
||||
# localName can be a unicode string, we're using attribute names as
|
||||
# **kwargs keys and python-level kwargs don't take unicode keys kindly
|
||||
# (they blow up) so we need to ensure all keys are ``str``
|
||||
return dict([(str(attrs.item(i).localName), attrs.item(i).nodeValue)
|
||||
for i in range(attrs.length)])
|
||||
|
||||
class Export(View):
|
||||
_cp_path = "/base/export"
|
||||
|
||||
def fields_get(self, req, model):
|
||||
Model = req.session.model(model)
|
||||
fields = Model.fields_get(False, req.session.eval_context(req.context))
|
||||
return fields
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get_fields(self, req, model, prefix='', name= '', field_parent=None, params={}):
|
||||
import_compat = params.get("import_compat", False)
|
||||
|
||||
fields = self.fields_get(req, model)
|
||||
field_parent_type = params.get("parent_field_type",False)
|
||||
|
||||
if import_compat and field_parent_type and field_parent_type == "many2one":
|
||||
fields = {}
|
||||
|
||||
fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
|
||||
records = []
|
||||
fields_order = fields.keys()
|
||||
fields_order.sort(lambda x,y: -cmp(fields[x].get('string', ''), fields[y].get('string', '')))
|
||||
|
||||
for index, field in enumerate(fields_order):
|
||||
value = fields[field]
|
||||
record = {}
|
||||
if import_compat and value.get('readonly', False):
|
||||
ok = False
|
||||
for sl in value.get('states', {}).values():
|
||||
for s in sl:
|
||||
ok = ok or (s==['readonly',False])
|
||||
if not ok: continue
|
||||
|
||||
id = prefix + (prefix and '/'or '') + field
|
||||
nm = name + (name and '/' or '') + value['string']
|
||||
record.update(id=id, string= nm, action='javascript: void(0)',
|
||||
target=None, icon=None, children=[], field_type=value.get('type',False), required=value.get('required', False))
|
||||
records.append(record)
|
||||
|
||||
if len(nm.split('/')) < 3 and value.get('relation', False):
|
||||
if import_compat:
|
||||
ref = value.pop('relation')
|
||||
cfields = self.fields_get(req, ref)
|
||||
if (value['type'] == 'many2many'):
|
||||
record['children'] = []
|
||||
record['params'] = {'model': ref, 'prefix': id, 'name': nm}
|
||||
|
||||
elif value['type'] == 'many2one':
|
||||
record['children'] = [id + '/id', id + '/.id']
|
||||
record['params'] = {'model': ref, 'prefix': id, 'name': nm}
|
||||
|
||||
else:
|
||||
cfields_order = cfields.keys()
|
||||
cfields_order.sort(lambda x,y: -cmp(cfields[x].get('string', ''), cfields[y].get('string', '')))
|
||||
children = []
|
||||
for j, fld in enumerate(cfields_order):
|
||||
cid = id + '/' + fld
|
||||
cid = cid.replace(' ', '_')
|
||||
children.append(cid)
|
||||
record['children'] = children or []
|
||||
record['params'] = {'model': ref, 'prefix': id, 'name': nm}
|
||||
else:
|
||||
ref = value.pop('relation')
|
||||
cfields = self.fields_get(req, ref)
|
||||
cfields_order = cfields.keys()
|
||||
cfields_order.sort(lambda x,y: -cmp(cfields[x].get('string', ''), cfields[y].get('string', '')))
|
||||
children = []
|
||||
for j, fld in enumerate(cfields_order):
|
||||
cid = id + '/' + fld
|
||||
cid = cid.replace(' ', '_')
|
||||
children.append(cid)
|
||||
record['children'] = children or []
|
||||
record['params'] = {'model': ref, 'prefix': id, 'name': nm}
|
||||
|
||||
records.reverse()
|
||||
return records
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def save_export_lists(self, req, name, model, field_list):
|
||||
result = {'resource':model, 'name':name, 'export_fields': []}
|
||||
for field in field_list:
|
||||
result['export_fields'].append((0, 0, {'name': field}))
|
||||
return req.session.model("ir.exports").create(result, req.session.eval_context(req.context))
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def exist_export_lists(self, req, model):
|
||||
export_model = req.session.model("ir.exports")
|
||||
return export_model.read(export_model.search([('resource', '=', model)]), ['name'])
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def delete_export(self, req, export_id):
|
||||
req.session.model("ir.exports").unlink(export_id, req.session.eval_context(req.context))
|
||||
return True
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def namelist(self,req, model, export_id):
|
||||
|
||||
result = self.get_data(req, model, req.session.eval_context(req.context))
|
||||
ir_export_obj = req.session.model("ir.exports")
|
||||
ir_export_line_obj = req.session.model("ir.exports.line")
|
||||
|
||||
field = ir_export_obj.read(export_id)
|
||||
fields = ir_export_line_obj.read(field['export_fields'])
|
||||
|
||||
name_list = {}
|
||||
[name_list.update({field['name']: result.get(field['name'])}) for field in fields]
|
||||
return name_list
|
||||
|
||||
def get_data(self, req, model, context=None):
|
||||
ids = []
|
||||
context = context or {}
|
||||
fields_data = {}
|
||||
proxy = req.session.model(model)
|
||||
fields = self.fields_get(req, model)
|
||||
if not ids:
|
||||
f1 = proxy.fields_view_get(False, 'tree', context)['fields']
|
||||
f2 = proxy.fields_view_get(False, 'form', context)['fields']
|
||||
|
||||
fields = dict(f1)
|
||||
fields.update(f2)
|
||||
fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
|
||||
|
||||
def rec(fields):
|
||||
_fields = {'id': 'ID' , '.id': 'Database ID' }
|
||||
def model_populate(fields, prefix_node='', prefix=None, prefix_value='', level=2):
|
||||
fields_order = fields.keys()
|
||||
fields_order.sort(lambda x,y: -cmp(fields[x].get('string', ''), fields[y].get('string', '')))
|
||||
|
||||
for field in fields_order:
|
||||
fields_data[prefix_node+field] = fields[field]
|
||||
if prefix_node:
|
||||
fields_data[prefix_node + field]['string'] = '%s%s' % (prefix_value, fields_data[prefix_node + field]['string'])
|
||||
st_name = fields[field]['string'] or field
|
||||
_fields[prefix_node+field] = st_name
|
||||
if fields[field].get('relation', False) and level>0:
|
||||
fields2 = self.fields_get(req, fields[field]['relation'])
|
||||
fields2.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
|
||||
model_populate(fields2, prefix_node+field+'/', None, st_name+'/', level-1)
|
||||
model_populate(fields)
|
||||
return _fields
|
||||
return rec(fields)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def export_data(self, req, model, fields, ids, domain, import_compat=False, export_format="csv", context=None):
|
||||
context = req.session.eval_context(req.context)
|
||||
modle_obj = req.session.model(model)
|
||||
ids = ids or modle_obj.search(domain, context=context)
|
||||
|
||||
field = fields.keys()
|
||||
result = modle_obj.export_data(ids, field , context).get('datas',[])
|
||||
|
||||
if not import_compat:
|
||||
field = [val.strip() for val in fields.values()]
|
||||
|
||||
if export_format == 'xls':
|
||||
return export_xls(field, result)
|
||||
else:
|
||||
return export_csv(field, result)
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
|
||||
v1.2.0 (c) Kyle Simpson
|
||||
MIT License
|
||||
*/
|
||||
(function(p){var q="string",w="head",L="body",M="script",u="readyState",j="preloaddone",x="loadtrigger",N="srcuri",E="preload",Z="complete",y="done",z="which",O="preserve",F="onreadystatechange",ba="onload",P="hasOwnProperty",bb="script/cache",Q="[object ",bw=Q+"Function]",bx=Q+"Array]",e=null,h=true,i=false,k=p.document,bc=p.location,bd=p.ActiveXObject,A=p.setTimeout,be=p.clearTimeout,R=function(a){return k.getElementsByTagName(a)},S=Object.prototype.toString,G=function(){},r={},T={},bf=/^[^?#]*\//.exec(bc.href)[0],bg=/^\w+\:\/\/\/?[^\/]+/.exec(bf)[0],by=R(M),bh=p.opera&&S.call(p.opera)==Q+"Opera]",bi=("MozAppearance"in k.documentElement.style),bj=(k.createElement(M).async===true),v={cache:!(bi||bh),order:bi||bh||bj,xhr:h,dupe:h,base:"",which:w};v[O]=i;v[E]=h;r[w]=k.head||R(w);r[L]=R(L);function B(a){return S.call(a)===bw}function U(a,b){var c=/^\w+\:\/\//,d;if(typeof a!=q)a="";if(typeof b!=q)b="";d=((/^\/\//.test(a))?bc.protocol:"")+a;d=(c.test(d)?"":b)+d;return((c.test(d)?"":(d.charAt(0)==="/"?bg:bf))+d)}function bz(a){return(U(a).indexOf(bg)===0)}function bA(a){var b,c=-1;while(b=by[++c]){if(typeof b.src==q&&a===U(b.src)&&b.type!==bb)return h}return i}function H(t,l){t=!(!t);if(l==e)l=v;var bk=i,C=t&&l[E],bl=C&&l.cache,I=C&&l.order,bm=C&&l.xhr,bB=l[O],bC=l.which,bD=l.base,bn=G,J=i,D,s=h,m={},K=[],V=e;C=bl||bm||I;function bo(a,b){if((a[u]&&a[u]!==Z&&a[u]!=="loaded")||b[y]){return i}a[ba]=a[F]=e;return h}function W(a,b,c){c=!(!c);if(!c&&!(bo(a,b)))return;b[y]=h;for(var d in m){if(m[P](d)&&!(m[d][y]))return}bk=h;bn()}function bp(a){if(B(a[x])){a[x]();a[x]=e}}function bE(a,b){if(!bo(a,b))return;b[j]=h;A(function(){r[b[z]].removeChild(a);bp(b)},0)}function bF(a,b){if(a[u]===4){a[F]=G;b[j]=h;A(function(){bp(b)},0)}}function X(b,c,d,g,f,n){var o=b[z];A(function(){if("item"in r[o]){if(!r[o][0]){A(arguments.callee,25);return}r[o]=r[o][0]}var a=k.createElement(M);if(typeof d==q)a.type=d;if(typeof g==q)a.charset=g;if(B(f)){a[ba]=a[F]=function(){f(a,b)};a.src=c;if(bj){a.async=i}}r[o].insertBefore(a,(o===w?r[o].firstChild:e));if(typeof n==q){a.text=n;W(a,b,h)}},0)}function bq(a,b,c,d){T[a[N]]=h;X(a,b,c,d,W)}function br(a,b,c,d){var g=arguments;if(s&&a[j]==e){a[j]=i;X(a,b,bb,d,bE)}else if(!s&&a[j]!=e&&!a[j]){a[x]=function(){br.apply(e,g)}}else if(!s){bq.apply(e,g)}}function bs(a,b,c,d){var g=arguments,f;if(s&&a[j]==e){a[j]=i;f=a.xhr=(bd?new bd("Microsoft.XMLHTTP"):new p.XMLHttpRequest());f[F]=function(){bF(f,a)};f.open("GET",b);f.send("")}else if(!s&&a[j]!=e&&!a[j]){a[x]=function(){bs.apply(e,g)}}else if(!s){T[a[N]]=h;X(a,b,c,d,e,a.xhr.responseText);a.xhr=e}}function bt(a){if(typeof a=="undefined"||!a)return;if(a.allowDup==e)a.allowDup=l.dupe;var b=a.src,c=a.type,d=a.charset,g=a.allowDup,f=U(b,bD),n,o=bz(f);if(typeof d!=q)d=e;g=!(!g);if(!g&&((T[f]!=e)||(s&&m[f])||bA(f))){if(m[f]!=e&&m[f][j]&&!m[f][y]&&o){W(e,m[f],h)}return}if(m[f]==e)m[f]={};n=m[f];if(n[z]==e)n[z]=bC;n[y]=i;n[N]=f;J=h;if(!I&&bm&&o)bs(n,f,c,d);else if(!I&&bl)br(n,f,c,d);else bq(n,f,c,d)}function Y(a){if(t&&!I)K.push(a);if(!t||C)a()}function bu(a){var b=[],c;for(c=-1;++c<a.length;){if(S.call(a[c])===bx)b=b.concat(bu(a[c]));else b[b.length]=a[c]}return b}D={script:function(){be(V);var a=bu(arguments),b=D,c;if(bB){for(c=-1;++c<a.length;){if(B(a[c]))a[c]=a[c]();if(c===0){Y(function(){bt((typeof a[0]==q)?{src:a[0]}:a[0])})}else b=b.script(a[c]);b=b.wait()}}else{for(c=-1;++c<a.length;){if(B(a[c]))a[c]=a[c]()}Y(function(){for(c=-1;++c<a.length;){bt((typeof a[c]==q)?{src:a[c]}:a[c])}})}V=A(function(){s=i},5);return b},wait:function(a){be(V);s=i;if(!B(a))a=G;var b=H(t||J,l),c=b.trigger,d=function(){try{a()}catch(err){}c()};delete b.trigger;var g=function(){if(J&&!bk)bn=d;else d()};if(t&&!J)K.push(g);else Y(g);return b}};if(t){D.trigger=function(){var a,b=-1;while(a=K[++b])a();K=[]}}else D.trigger=G;return D}function bv(a){var b,c={},d={"UseCachePreload":"cache","UseLocalXHR":"xhr","UsePreloading":E,"AlwaysPreserveOrder":O,"AllowDuplicates":"dupe"},g={"AppendTo":z,"BasePath":"base"};for(b in d)g[b]=d[b];c.order=!(!v.order);for(b in g){if(g[P](b)&&v[g[b]]!=e)c[g[b]]=(a[b]!=e)?a[b]:v[g[b]]}for(b in d){if(d[P](b))c[d[b]]=!(!c[d[b]])}if(!c[E])c.cache=c.order=c.xhr=i;c.which=(c.which===w||c.which===L)?c.which:w;return c}p.$LAB={setGlobalDefaults:function(a){v=bv(a)},setOptions:function(a){return H(i,bv(a))},script:function(){return H().script.apply(e,arguments)},wait:function(){return H().wait.apply(e,arguments)}};(function(a,b,c){if(k[u]==e&&k[a]){k[u]="loading";k[a](b,c=function(){k.removeEventListener(b,c,i);k[u]=Z},i)}})("addEventListener","DOMContentLoaded")})(window);
|
|
@ -304,6 +304,7 @@ QWeb2.Engine = (function() {
|
|||
" /* START TEMPLATE */ try {\n" +
|
||||
(e.compile()) + "\n" +
|
||||
" /* END OF TEMPLATE */ } catch(error) {\n" +
|
||||
" if (console && console.exception) console.exception(error);\n" +
|
||||
" context.engine.tools.exception('Runtime Error: ' + error, context);\n" +
|
||||
" }\n" +
|
||||
" return r.join('');";
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html style="height: 100%">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP</title>
|
||||
<link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
|
||||
<script type="text/javascript" src="/base/static/lib/LABjs/LAB.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/underscore/underscore.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/underscore/underscore.string.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/qweb/qweb2.js"></script>
|
||||
<!-- Uncomment in order to use legacy QWeb
|
||||
<script type="text/javascript" src="/base/static/lib/qweb/qweb.js"></script>
|
||||
-->
|
||||
<script type="text/javascript" src="/base/static/lib/jquery/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ui.notify/js/jquery.notify.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.superfish/js/hoverIntent.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.superfish/js/superfish.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/datejs/date-en-US.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/json/json2.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/base.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/dates.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/chrome.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/data.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/views.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/form.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/list.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/list-editable.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/tree.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/search.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/base/static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css" />
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/base/static/lib/jquery.ui.notify/css/ui.notify.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/base/static/lib/jquery.superfish/css/superfish.css" media="screen">
|
||||
|
||||
<link rel="stylesheet" href="/base/static/src/css/base.css" type="text/css"/>
|
||||
<!--[if lte IE 7]>
|
||||
<link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
|
||||
<![endif]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
QWeb = window.QWeb || new QWeb2.Engine();
|
||||
var oe = openerp.init();
|
||||
oe.base.webclient("oe");
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body id="oe" class="openerp">
|
||||
</body>
|
||||
</html>
|
|
@ -30,6 +30,9 @@ body.openerp {
|
|||
.openerp .oe-number {
|
||||
text-align: right !important;
|
||||
}
|
||||
.openerp .oe_hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* STATES */
|
||||
.openerp .on_logged {
|
||||
|
@ -577,6 +580,10 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
display: none;
|
||||
}
|
||||
|
||||
.openerp .searchview_extended_delete_prop {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.openerp .searchview_extended_delete_group span,
|
||||
.openerp .searchview_extended_delete_prop span {
|
||||
font-size: 0.9em;
|
||||
|
@ -591,6 +598,10 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
border: 1px solid silver;
|
||||
}
|
||||
|
||||
.openerp .oe-listview thead table {
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
.openerp .oe-listview tr.odd {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
@ -600,16 +611,27 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
.openerp .oe-listview tbody tr:hover {
|
||||
background-color: #eae9f0;
|
||||
}
|
||||
.openerp .oe-listview thead table tr,
|
||||
.openerp .oe-listview thead table tr:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.openerp .oe-listview td,
|
||||
.openerp .oe-listview th {
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
}
|
||||
.openerp .oe-listview th.oe-sortable,
|
||||
.openerp .oe-listview th.oe-sortable .ui-icon {
|
||||
.openerp .oe-listview td.oe-record-delete {
|
||||
text-align: right;
|
||||
}
|
||||
.openerp .oe-listview th.oe-sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.openerp .oe-listview th.oe-sortable .ui-icon {
|
||||
height: 1em;
|
||||
display: inline;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.openerp .oe-listview .oe-field-cell {
|
||||
cursor: pointer;
|
||||
|
@ -632,9 +654,22 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
|
||||
.openerp .oe-listview th.oe-actions {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.openerp .oe-listview th.oe-list-pager {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.openerp .oe-list-pager .oe-pager-state {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.openerp .oe-listview .oe-group-name {
|
||||
padding-right: 1em;
|
||||
}
|
||||
.openerp .oe-listview .oe-group-name,
|
||||
.openerp .oe-listview .oe-group-pagination {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.openerp .oe-listview tfoot td {
|
||||
|
@ -653,29 +688,29 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
rounded corners are a pain on tables: need to round not only table, but
|
||||
also on the first and last children of the first and last row
|
||||
*/
|
||||
.openerp .oe-listview table {
|
||||
.openerp .oe-listview table.oe-listview-content {
|
||||
-webkit-border-radius: 7px;
|
||||
-moz-border-radius: 7px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
.openerp .oe-listview table thead tr:first-child th:first-child {
|
||||
.openerp .oe-listview table.oe-listview-content thead tr:first-child th:first-child {
|
||||
-webkit-border-top-left-radius: 7px;
|
||||
-moz-border-radius-topleft: 7px;
|
||||
border-top-left-radius: 7px;
|
||||
}
|
||||
.openerp .oe-listview table thead tr:first-child th:last-child {
|
||||
.openerp .oe-listview table.oe-listview-content thead tr:first-child th:last-child {
|
||||
-webkit-border-top-right-radius: 7px;
|
||||
-moz-border-radius-topright: 7px;
|
||||
border-top-right-radius: 7px;
|
||||
}
|
||||
.openerp .oe-listview table tfoot td:first-child,
|
||||
.openerp .oe-listview table tbody:last-child tr:last-child th:first-child {
|
||||
.openerp .oe-listview table.oe-listview-content tfoot td:first-child,
|
||||
.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child th:first-child {
|
||||
-webkit-border-bottom-left-radius: 7px;
|
||||
-moz-border-radius-bottomleft: 7px;
|
||||
border-bottom-left-radius: 7px;
|
||||
}
|
||||
.openerp .oe-listview table tfoot td:last-child,
|
||||
.openerp .oe-listview table tbody:last-child tr:last-child td:last-child {
|
||||
.openerp .oe-listview table.oe-listview-content tfoot td:last-child,
|
||||
.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child td:last-child {
|
||||
-webkit-border-bottom-right-radius: 7px;
|
||||
-moz-border-radius-bottomright: 7px;
|
||||
border-bottom-right-radius: 7px;
|
||||
|
@ -773,13 +808,14 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
position: relative;
|
||||
vertical-align: top;
|
||||
}
|
||||
.openerp input.field_date, .openerp input.field_datetime {
|
||||
background: #fff url('../img/ui/field_calendar.png') no-repeat right center;
|
||||
background-origin: content-box;
|
||||
-moz-background-origin: content;
|
||||
-moz-background-origin: content-box;
|
||||
-webkit-background-origin: content-box;
|
||||
.openerp img.ui-datepicker-trigger, .openerp img.ui-datepicker-trigger {
|
||||
margin-left: -20px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
/* http://www.quirksmode.org/dom/inputfile.html
|
||||
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
|
||||
*/
|
||||
|
@ -987,6 +1023,10 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
|
|||
.openerp .closed-sidebar .toggle-sidebar {
|
||||
border-left: none;
|
||||
}
|
||||
.openerp li.oe_sidebar_print {
|
||||
padding-left: 20px;
|
||||
background: 1px 3px url(../img/icons/gtk-print.png) no-repeat;
|
||||
}
|
||||
|
||||
.openerp.kitten-mode-activated .main_table {
|
||||
background: url(http://placekitten.com/g/1500/800) repeat;
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
.openerp .oe_export_row tr{
|
||||
background-color: #FFFFFF;
|
||||
font-size: 0.8em;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.openerp tr.ui-selected td {
|
||||
background-color: #CCCCCC;
|
||||
}
|
||||
|
||||
.openerp .oe_export_requiredfield {
|
||||
background-color: #D2D2FF;
|
||||
}
|
||||
|
||||
.openerp .oe_export_readonlyfield{
|
||||
background-color: #999999;
|
||||
}
|
||||
|
||||
.openerp .oe_export_row:hover{
|
||||
background-color: #F3F3F3;
|
||||
}
|
||||
|
||||
.openerp .oe_export_fields_selector_export {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.openerp .oe_export_fields_selector_left {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.openerp div#left_field_panel {
|
||||
overflow: scroll;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border: solid #999999 1px;
|
||||
}
|
||||
|
||||
.openerp .oe_export_fields_selector_center {
|
||||
width: 102px;
|
||||
}
|
||||
|
||||
.openerp .oe_export_fields_selector_right {
|
||||
width: 45%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.openerp .oe_export_fields_selector_export select{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.openerp .oe_export_tree_header{
|
||||
border: 0.5px solid #E3E3E3;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
padding: 4px 5px;
|
||||
background: url(/base/static/src/img/header.gif);
|
||||
}
|
||||
|
||||
|
||||
.openerp table.tree_grid{
|
||||
border: 1px solid #E3E3E3;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
background-color:#E3E3E3;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.openerp table.tree_grid a:hover {
|
||||
color: blue;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.openerp table.tree_grid a {
|
||||
color: #5F5C5C;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.openerp .oe_export_button_export {
|
||||
border: 1px solid #006;
|
||||
background-color: #F3F3F3;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 80 B |
Binary file not shown.
After Width: | Height: | Size: 81 B |
Binary file not shown.
After Width: | Height: | Size: 182 B |
|
@ -1,71 +1,5 @@
|
|||
/*---------------------------------------------------------
|
||||
* John Resig Class, to be moved to openerp.base.Class
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
(function() {
|
||||
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
// The base Class implementation (does nothing)
|
||||
this.Class = function(){};
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Class.extend = function(prop) {
|
||||
var _super = this.prototype;
|
||||
|
||||
// Instantiate a base class (but only create the instance,
|
||||
// don't run the init constructor)
|
||||
initializing = true;
|
||||
var prototype = new this();
|
||||
initializing = false;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
for (var name in prop) {
|
||||
// Check if we're overwriting an existing function
|
||||
prototype[name] = typeof prop[name] == "function" &&
|
||||
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
|
||||
(function(name, fn){
|
||||
return function() {
|
||||
var tmp = this._super;
|
||||
|
||||
// Add a new ._super() method that is the same method
|
||||
// but on the super-class
|
||||
this._super = _super[name];
|
||||
|
||||
// The method only need to be bound temporarily, so we
|
||||
// remove it when we're done executing
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
|
||||
return ret;
|
||||
};
|
||||
})(name, prop[name]) :
|
||||
prop[name];
|
||||
}
|
||||
|
||||
// The dummy class constructor
|
||||
function Class() {
|
||||
// All construction is actually done in the init method
|
||||
if ( !initializing && this.init ) {
|
||||
var ret = this.init.apply(this, arguments);
|
||||
if (ret) { return ret; }
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.constructor = Class;
|
||||
|
||||
// And make this class extendable
|
||||
Class.extend = arguments.callee;
|
||||
|
||||
return Class;
|
||||
};
|
||||
})();
|
||||
|
||||
//---------------------------------------------------------
|
||||
// OpenERP initialisation and black magic about the pool
|
||||
// OpenERP Web Boostrap
|
||||
//---------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -107,11 +41,13 @@
|
|||
_session_id: "session" + session_counter++,
|
||||
screen: openerp.screen,
|
||||
sessions: openerp.sessions,
|
||||
base: {}
|
||||
base: {},
|
||||
web_mobile: {}
|
||||
};
|
||||
openerp.sessions[new_instance._session_id] = new_instance;
|
||||
if (!skip_init)
|
||||
if (!skip_init){
|
||||
openerp.base(new_instance);
|
||||
}
|
||||
return new_instance;
|
||||
}
|
||||
};
|
||||
|
@ -121,8 +57,8 @@
|
|||
// OpenERP base module split
|
||||
//---------------------------------------------------------
|
||||
|
||||
/** @namespace */
|
||||
openerp.base = function(instance) {
|
||||
openerp.base.core(instance);
|
||||
openerp.base.dates(instance);
|
||||
openerp.base.chrome(instance);
|
||||
openerp.base.data(instance);
|
||||
|
@ -135,9 +71,6 @@ openerp.base = function(instance) {
|
|||
if (openerp.base.list) {
|
||||
openerp.base.list(instance);
|
||||
}
|
||||
if (openerp.base.tree) {
|
||||
openerp.base.tree(instance);
|
||||
}
|
||||
if (openerp.base. m2o) {
|
||||
openerp.base.m2o(instance);
|
||||
}
|
||||
|
@ -147,6 +80,15 @@ openerp.base = function(instance) {
|
|||
if (openerp.base.list && openerp.base.list.editable) {
|
||||
openerp.base.list.editable(instance);
|
||||
}
|
||||
if (openerp.web_mobile) {
|
||||
openerp.web_mobile(instance);
|
||||
}
|
||||
if (openerp.base.view_tree) {
|
||||
openerp.base.view_tree(instance);
|
||||
}
|
||||
if (openerp.base.data_export) {
|
||||
openerp.base.data_export(instance);
|
||||
}
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
|
@ -4,325 +4,15 @@
|
|||
|
||||
openerp.base.chrome = function(openerp) {
|
||||
|
||||
openerp.base.callback = function(obj, method) {
|
||||
var callback = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var r;
|
||||
for(var i = 0; i < callback.callback_chain.length; i++) {
|
||||
var c = callback.callback_chain[i];
|
||||
if(c.unique) {
|
||||
callback.callback_chain.splice(i, 1);
|
||||
i -= 1;
|
||||
}
|
||||
r = c.callback.apply(c.self, c.args.concat(args));
|
||||
// TODO special value to stop the chain
|
||||
// openerp.base.callback_stop
|
||||
}
|
||||
return r;
|
||||
};
|
||||
callback.callback_chain = [];
|
||||
callback.add = function(f) {
|
||||
if(typeof(f) == 'function') {
|
||||
f = { callback: f, args: Array.prototype.slice.call(arguments, 1) };
|
||||
}
|
||||
f.self = f.self || null;
|
||||
f.args = f.args || [];
|
||||
f.unique = !!f.unique;
|
||||
if(f.position == 'last') {
|
||||
callback.callback_chain.push(f);
|
||||
} else {
|
||||
callback.callback_chain.unshift(f);
|
||||
}
|
||||
return callback;
|
||||
};
|
||||
callback.add_first = function(f) {
|
||||
return callback.add.apply(null,arguments);
|
||||
};
|
||||
callback.add_last = function(f) {
|
||||
return callback.add({
|
||||
callback: f,
|
||||
args: Array.prototype.slice.call(arguments, 1),
|
||||
position: "last"
|
||||
});
|
||||
};
|
||||
|
||||
return callback.add({
|
||||
callback: method,
|
||||
self:obj,
|
||||
args:Array.prototype.slice.call(arguments, 2)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Base error for lookup failure
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
openerp.base.NotFound = Class.extend( /** @lends openerp.base.NotFound# */ {
|
||||
});
|
||||
openerp.base.KeyNotFound = openerp.base.NotFound.extend( /** @lends openerp.base.KeyNotFound# */ {
|
||||
/**
|
||||
* Thrown when a key could not be found in a mapping
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.NotFound
|
||||
* @param {String} key the key which could not be found
|
||||
*/
|
||||
init: function (key) {
|
||||
this.key = key;
|
||||
},
|
||||
toString: function () {
|
||||
return "The key " + this.key + " was not found";
|
||||
}
|
||||
});
|
||||
openerp.base.ObjectNotFound = openerp.base.NotFound.extend( /** @lends openerp.base.ObjectNotFound# */ {
|
||||
/**
|
||||
* Thrown when an object path does not designate a valid class or object
|
||||
* in the openerp hierarchy.
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.NotFound
|
||||
* @param {String} path the invalid object path
|
||||
*/
|
||||
init: function (path) {
|
||||
this.path = path;
|
||||
},
|
||||
toString: function () {
|
||||
return "Could not find any object of path " + this.path;
|
||||
}
|
||||
});
|
||||
openerp.base.Registry = Class.extend( /** @lends openerp.base.Registry# */ {
|
||||
/**
|
||||
* Stores a mapping of arbitrary key (strings) to object paths (as strings
|
||||
* as well).
|
||||
*
|
||||
* Resolves those paths at query time in order to always fetch the correct
|
||||
* object, even if those objects have been overloaded/replaced after the
|
||||
* registry was created.
|
||||
*
|
||||
* An object path is simply a dotted name from the openerp root to the
|
||||
* object pointed to (e.g. ``"openerp.base.Session"`` for an OpenERP
|
||||
* session object).
|
||||
*
|
||||
* @constructs
|
||||
* @param {Object} mapping a mapping of keys to object-paths
|
||||
*/
|
||||
init: function (mapping) {
|
||||
this.map = mapping || {};
|
||||
},
|
||||
/**
|
||||
* Retrieves the object matching the provided key string.
|
||||
*
|
||||
* @param {String} key the key to fetch the object for
|
||||
* @returns {Class} the stored class, to initialize
|
||||
*
|
||||
* @throws {openerp.base.KeyNotFound} if the object was not in the mapping
|
||||
* @throws {openerp.base.ObjectNotFound} if the object path was invalid
|
||||
*/
|
||||
get_object: function (key) {
|
||||
var path_string = this.map[key];
|
||||
if (path_string === undefined) {
|
||||
throw new openerp.base.KeyNotFound(key);
|
||||
}
|
||||
|
||||
var object_match = openerp;
|
||||
var path = path_string.split('.');
|
||||
// ignore first section
|
||||
for(var i=1; i<path.length; ++i) {
|
||||
object_match = object_match[path[i]];
|
||||
|
||||
if (object_match === undefined) {
|
||||
throw new openerp.base.ObjectNotFound(path_string);
|
||||
}
|
||||
}
|
||||
return object_match;
|
||||
},
|
||||
/**
|
||||
* Tries a number of keys, and returns the first object matching one of
|
||||
* the keys.
|
||||
*
|
||||
* @param {Array} keys a sequence of keys to fetch the object for
|
||||
* @returns {Class} the first class found matching an object
|
||||
*
|
||||
* @throws {openerp.base.KeyNotFound} if none of the keys was in the mapping
|
||||
* @trows {openerp.base.ObjectNotFound} if a found object path was invalid
|
||||
*/
|
||||
get_any: function (keys) {
|
||||
for (var i=0; i<keys.length; ++i) {
|
||||
try {
|
||||
return this.get_object(keys[i]);
|
||||
} catch (e) {
|
||||
if (e instanceof openerp.base.KeyNotFound) {
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
throw new openerp.base.KeyNotFound(keys.join(','));
|
||||
},
|
||||
/**
|
||||
* Adds a new key and value to the registry.
|
||||
*
|
||||
* This method can be chained.
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {String} object_path fully qualified dotted object path
|
||||
* @returns {openerp.base.Registry} itself
|
||||
*/
|
||||
add: function (key, object_path) {
|
||||
this.map[key] = object_path;
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Creates and returns a copy of the current mapping, with the provided
|
||||
* mapping argument added in (replacing existing keys if needed)
|
||||
*
|
||||
* @param {Object} [mapping={}] a mapping of keys to object-paths
|
||||
*/
|
||||
clone: function (mapping) {
|
||||
return new openerp.base.Registry(
|
||||
_.extend({}, this.map, mapping || {}));
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.BasicController = Class.extend( /** @lends openerp.base.BasicController# */{
|
||||
/**
|
||||
* rpc operations, event binding and callback calling should be done in
|
||||
* start() instead of init so that event can be hooked in between.
|
||||
*
|
||||
* @constructs
|
||||
*/
|
||||
init: function(element_id) {
|
||||
this.element_id = element_id;
|
||||
this.$element = $('#' + element_id);
|
||||
if (element_id) {
|
||||
openerp.screen[element_id] = this;
|
||||
}
|
||||
|
||||
// Transform on_* method into openerp.base.callbacks
|
||||
for (var name in this) {
|
||||
if(typeof(this[name]) == "function") {
|
||||
this[name].debug_name = name;
|
||||
// bind ALL function to this not only on_and _do ?
|
||||
if((/^on_|^do_/).test(name)) {
|
||||
this[name] = openerp.base.callback(this, this[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Controller start
|
||||
* event binding, rpc and callback calling required to initialize the
|
||||
* object can happen here
|
||||
*
|
||||
* Returns a promise object letting callers (subclasses and direct callers)
|
||||
* know when this component is done starting
|
||||
*
|
||||
* @returns {jQuery.Deferred}
|
||||
*/
|
||||
start: function() {
|
||||
// returns an already fulfilled promise. Maybe we could return nothing?
|
||||
// $.when can take non-deferred and in that case it simply considers
|
||||
// them all as fulfilled promises.
|
||||
// But in thise case we *have* to ensure callers use $.when and don't
|
||||
// try to call deferred methods on this return value.
|
||||
return $.Deferred().done().promise();
|
||||
},
|
||||
stop: function() {
|
||||
},
|
||||
log: function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var caller = arguments.callee.caller;
|
||||
// TODO add support for line number using
|
||||
// https://github.com/emwendelin/javascript-stacktrace/blob/master/stacktrace.js
|
||||
// args.unshift("" + caller.debug_name);
|
||||
this.on_log.apply(this,args);
|
||||
},
|
||||
on_log: function() {
|
||||
if(window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) {
|
||||
var notify = false;
|
||||
var body = false;
|
||||
if(window.console) {
|
||||
console.log(arguments);
|
||||
} else {
|
||||
body = true;
|
||||
}
|
||||
var a = Array.prototype.slice.call(arguments, 0);
|
||||
for(var i = 0; i < a.length; i++) {
|
||||
var v = a[i]==null ? "null" : a[i].toString();
|
||||
if(i==0) {
|
||||
notify = v.match(/^not/);
|
||||
body = v.match(/^bod/);
|
||||
}
|
||||
if(body) {
|
||||
$('<pre></pre>').text(v).appendTo($('body'));
|
||||
}
|
||||
if(notify && this.notification) {
|
||||
this.notification.notify("Logging:",v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Generates an inherited class that replaces all the methods by null methods (methods
|
||||
* that does nothing and always return undefined).
|
||||
*
|
||||
* @param {Class} claz
|
||||
* @param {dict} add Additional functions to override.
|
||||
* @return {Class}
|
||||
*/
|
||||
openerp.base.generate_null_object_class = function(claz, add) {
|
||||
var newer = {};
|
||||
var copy_proto = function(prototype) {
|
||||
for (var name in prototype) {
|
||||
if(typeof prototype[name] == "function") {
|
||||
newer[name] = function() {};
|
||||
}
|
||||
}
|
||||
if (prototype.prototype)
|
||||
copy_proto(prototype.prototype);
|
||||
};
|
||||
copy_proto(claz.prototype);
|
||||
newer.init = openerp.base.BasicController.prototype.init;
|
||||
var tmpclass = claz.extend(newer);
|
||||
return tmpclass.extend(add || {});
|
||||
};
|
||||
|
||||
openerp.base.Notification = openerp.base.BasicController.extend({
|
||||
init: function(element_id) {
|
||||
this._super(element_id);
|
||||
this.$element.notify({
|
||||
speed: 500,
|
||||
expires: 1500
|
||||
});
|
||||
},
|
||||
notify: function(title, text) {
|
||||
this.$element.notify('create', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
},
|
||||
warn: function(title, text) {
|
||||
this.$element.notify('create', 'oe_notification_alert', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.base.Session# */{
|
||||
openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{
|
||||
/**
|
||||
* @constructs
|
||||
* @extends openerp.base.BasicController
|
||||
* @param element_id to use for exception reporting
|
||||
* @param server
|
||||
* @param port
|
||||
*/
|
||||
init: function(element_id, server, port) {
|
||||
this._super(element_id);
|
||||
init: function(parent, element_id, server, port) {
|
||||
this._super(parent, element_id);
|
||||
this.server = (server == undefined) ? location.hostname : server;
|
||||
this.port = (port == undefined) ? location.port : port;
|
||||
this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp";
|
||||
|
@ -350,15 +40,12 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
* @param {Object} params call parameters
|
||||
* @param {Function} success_callback function to execute on RPC call success
|
||||
* @param {Function} error_callback function to execute on RPC call failure
|
||||
* one
|
||||
* @returns {jQuery.Deferred} jquery-provided ajax deferred
|
||||
*/
|
||||
rpc: function(url, params, success_callback, error_callback) {
|
||||
var self = this;
|
||||
// Construct a JSON-RPC2 request, method is currently unused
|
||||
params.session_id = this.session_id;
|
||||
// niv: wtf?
|
||||
//params.context = typeof(params.context) != "undefined" ? params.context : this.context;
|
||||
|
||||
// Call using the rpc_mode
|
||||
var deferred = $.Deferred();
|
||||
|
@ -368,7 +55,7 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
params: params,
|
||||
id:null
|
||||
}).then(function () {deferred.resolve.apply(deferred, arguments);},
|
||||
function(error) {deferred.reject(error, $.Event());});
|
||||
function(error) {deferred.reject(error, $.Event());});
|
||||
return deferred.fail(function() {
|
||||
deferred.fail(function(error, event) {
|
||||
if (!event.isDefaultPrevented()) {
|
||||
|
@ -401,30 +88,35 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
}, url);
|
||||
var deferred = $.Deferred();
|
||||
$.ajax(ajax).done(function(response, textStatus, jqXHR) {
|
||||
self.on_rpc_response();
|
||||
if (response.error) {
|
||||
if (response.error.data.type == "session_invalid") {
|
||||
self.uid = false;
|
||||
self.on_session_invalid(function() {
|
||||
self.rpc(url, payload.params,
|
||||
function() {deferred.resolve.apply(deferred, arguments);},
|
||||
function() {deferred.reject.apply(deferred, arguments);});
|
||||
});
|
||||
} else {
|
||||
deferred.reject(response.error);
|
||||
}
|
||||
} else {
|
||||
deferred.resolve(response["result"], textStatus, jqXHR);
|
||||
}
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
self.on_rpc_response();
|
||||
var error = {
|
||||
code: -32098,
|
||||
message: "XmlHttpRequestError " + errorThrown,
|
||||
data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] }
|
||||
};
|
||||
deferred.reject(error);
|
||||
self.on_rpc_response();
|
||||
if (!response.error) {
|
||||
deferred.resolve(response["result"], textStatus, jqXHR);
|
||||
return;
|
||||
}
|
||||
if (response.error.data.type !== "session_invalid") {
|
||||
deferred.reject(response.error);
|
||||
return;
|
||||
}
|
||||
self.uid = false;
|
||||
self.on_session_invalid(function() {
|
||||
self.rpc(url, payload.params,
|
||||
function() {
|
||||
deferred.resolve.apply(deferred, arguments);
|
||||
},
|
||||
function(error, event) {
|
||||
event.preventDefault();
|
||||
deferred.reject.apply(deferred, arguments);
|
||||
});
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
self.on_rpc_response();
|
||||
var error = {
|
||||
code: -32098,
|
||||
message: "XmlHttpRequestError " + errorThrown,
|
||||
data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] }
|
||||
};
|
||||
deferred.reject(error);
|
||||
});
|
||||
return deferred.promise();
|
||||
},
|
||||
on_rpc_request: function() {
|
||||
|
@ -499,7 +191,7 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
for(var i=0; i<cookies.length; ++i) {
|
||||
var cookie = cookies[i].replace(/^\s*/, '');
|
||||
if(cookie.indexOf(nameEQ) === 0) {
|
||||
return decodeURIComponent(cookie.substring(nameEQ.length));
|
||||
return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -515,7 +207,7 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
set_cookie: function (name, value, ttl) {
|
||||
ttl = ttl || 24*60*60*365;
|
||||
document.cookie = [
|
||||
this.element_id + '|' + name + '=' + encodeURIComponent(value),
|
||||
this.element_id + '|' + name + '=' + encodeURIComponent(JSON.stringify(value)),
|
||||
'max-age=' + ttl,
|
||||
'expires=' + new Date(new Date().getTime() + ttl*1000).toGMTString()
|
||||
].join(';');
|
||||
|
@ -526,15 +218,20 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
load_modules: function() {
|
||||
var self = this;
|
||||
this.rpc('/base/session/modules', {}, function(result) {
|
||||
self.module_list = result['modules'];
|
||||
self.module_list = result;
|
||||
var modules = self.module_list.join(',');
|
||||
self.rpc('/base/session/csslist', {mods: modules}, self.do_load_css);
|
||||
self.rpc('/base/session/jslist', {"mods": modules}, self.debug ? self.do_load_modules_debug : self.do_load_modules_prod);
|
||||
if(self.debug || true) {
|
||||
self.rpc('/base/webclient/csslist', {"mods": modules}, self.do_load_css);
|
||||
self.rpc('/base/webclient/jslist', {"mods": modules}, self.do_load_js);
|
||||
} else {
|
||||
self.do_load_css(["/base/webclient/css?mods="+modules]);
|
||||
self.do_load_js(["/base/webclient/js?mods="+modules]);
|
||||
}
|
||||
openerp._modules_loaded = true;
|
||||
});
|
||||
},
|
||||
do_load_css: function (result) {
|
||||
_.each(result.files, function (file) {
|
||||
do_load_css: function (files) {
|
||||
_.each(files, function (file) {
|
||||
$('head').append($('<link>', {
|
||||
'href': file,
|
||||
'rel': 'stylesheet',
|
||||
|
@ -542,16 +239,23 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
}));
|
||||
});
|
||||
},
|
||||
do_load_modules_debug: function(result) {
|
||||
$LAB.setOptions({AlwaysPreserveOrder: true})
|
||||
.script(result.files)
|
||||
.wait(this.on_modules_loaded);
|
||||
},
|
||||
do_load_modules_prod: function() {
|
||||
// load merged ones
|
||||
// /base/session/css?mod=mod1,mod2,mod3
|
||||
// /base/session/js?mod=mod1,mod2,mod3
|
||||
// use $.getScript(‘your_3rd_party-script.js’); ? i want to keep lineno !
|
||||
do_load_js: function(files) {
|
||||
var self = this;
|
||||
if(files.length != 0) {
|
||||
var file = files.shift();
|
||||
var tag = document.createElement('script');
|
||||
tag.type = 'text/javascript';
|
||||
tag.src = file;
|
||||
tag.onload = tag.onreadystatechange = function() {
|
||||
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
|
||||
return;
|
||||
tag.onload_done = true;
|
||||
self.do_load_js(files);
|
||||
};
|
||||
document.head.appendChild(tag);
|
||||
} else {
|
||||
this.on_modules_loaded();
|
||||
}
|
||||
},
|
||||
on_modules_loaded: function() {
|
||||
for(var j=0; j<this.module_list.length; j++) {
|
||||
|
@ -568,209 +272,34 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
|||
}
|
||||
});
|
||||
|
||||
// A controller takes an already existing element
|
||||
// new()
|
||||
// start()
|
||||
openerp.base.Controller = openerp.base.BasicController.extend( /** @lends openerp.base.Controller# */{
|
||||
/**
|
||||
* Controller manifest used to declare standard controller attributes
|
||||
*/
|
||||
controller_manifest: {
|
||||
register: null,
|
||||
template: "",
|
||||
element_post_prefix: false
|
||||
},
|
||||
/**
|
||||
* Controller registry,
|
||||
*/
|
||||
controller_registry: {
|
||||
},
|
||||
/**
|
||||
* Add a new child controller
|
||||
*/
|
||||
controller_get: function(key) {
|
||||
return this.controller_registry[key];
|
||||
// OR should build it ? setting parent correctly ?
|
||||
// function construct(constructor, args) {
|
||||
// function F() {
|
||||
// return constructor.apply(this, args);
|
||||
// }
|
||||
// F.prototype = constructor.prototype;
|
||||
// return new F();
|
||||
// }
|
||||
// var obj = this.controller_registry[key];
|
||||
// if(obj) {
|
||||
// return construct(obj, Array.prototype.slice.call(arguments, 1));
|
||||
// }
|
||||
},
|
||||
controller_new: function(key) {
|
||||
var self;
|
||||
// OR should contrustct it ? setting parent correctly ?
|
||||
function construct(constructor, args) {
|
||||
function F() {
|
||||
return constructor.apply(this, args);
|
||||
}
|
||||
F.prototype = constructor.prototype;
|
||||
return new F();
|
||||
}
|
||||
var obj = this.controller_registry[key];
|
||||
if(obj) {
|
||||
// TODO Prepend parent
|
||||
return construct(obj, Array.prototype.slice.call(arguments, 1));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @constructs
|
||||
* @extends openerp.base.BasicController
|
||||
*/
|
||||
init: function(parent_or_session, element_id) {
|
||||
this._super(element_id);
|
||||
this.controller_parent = null;
|
||||
this.controller_children = [];
|
||||
if(parent_or_session) {
|
||||
if(parent_or_session.session) {
|
||||
this.parent = parent_or_session;
|
||||
this.session = this.parent.session;
|
||||
if(this.parent.children) {
|
||||
this.parent.children.push(this);
|
||||
}
|
||||
} else {
|
||||
// TODO remove Backward compatilbility
|
||||
this.session = parent_or_session;
|
||||
}
|
||||
}
|
||||
// Apply manifest options
|
||||
if(this.controller_manifest) {
|
||||
var register = this.controller_manifest.register;
|
||||
// TODO accept a simple string
|
||||
if(register) {
|
||||
for(var i=0; i<register.length; i++) {
|
||||
this.controller_registry[register[i]] = this;
|
||||
}
|
||||
}
|
||||
// TODO if post prefix
|
||||
//this.element_id = _.uniqueId(_.toArray(arguments).join('_'));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Performs a JSON-RPC call
|
||||
*
|
||||
* @param {String} url endpoint url
|
||||
* @param {Object} data RPC parameters
|
||||
* @param {Function} success RPC call success callback
|
||||
* @param {Function} error RPC call error callback
|
||||
* @returns {jQuery.Deferred} deferred object for the RPC call
|
||||
*/
|
||||
rpc: function(url, data, success, error) {
|
||||
// TODO: support additional arguments ?
|
||||
return this.session.rpc(url, data, success, error);
|
||||
}
|
||||
});
|
||||
|
||||
// A widget is a controller that doesnt take an element_id
|
||||
// it render its own html that you should insert into the dom
|
||||
// and bind it a start()
|
||||
//
|
||||
// new()
|
||||
// render() and insert it place it where you want
|
||||
// start()
|
||||
openerp.base.BaseWidget = openerp.base.Controller.extend({
|
||||
/**
|
||||
* The name of the QWeb template that will be used for rendering. Must be
|
||||
* redefined in subclasses or the render() method can not be used.
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
template: null,
|
||||
/**
|
||||
* The prefix used to generate an id automatically. Should be redefined in
|
||||
* subclasses. If it is not defined, a default identifier will be used.
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
identifier_prefix: 'generic-identifier',
|
||||
/**
|
||||
* Base class for widgets. Handle rendering (based on a QWeb template),
|
||||
* identifier generation, parenting and destruction of the widget.
|
||||
* Also initialize the identifier.
|
||||
*
|
||||
* @constructs
|
||||
* @params {openerp.base.search.BaseWidget} parent The parent widget.
|
||||
*/
|
||||
init: function (parent, session) {
|
||||
this._super(session);
|
||||
this.children = [];
|
||||
this.parent = null;
|
||||
this.set_parent(parent);
|
||||
this.make_id(this.identifier_prefix);
|
||||
},
|
||||
/**
|
||||
* Sets and returns a globally unique identifier for the widget.
|
||||
*
|
||||
* If a prefix is appended, the identifier will be appended to it.
|
||||
*
|
||||
* @params sections prefix sections, empty/falsy sections will be removed
|
||||
*/
|
||||
make_id: function () {
|
||||
this.element_id = _.uniqueId(_.toArray(arguments).join('_'));
|
||||
return this.element_id;
|
||||
},
|
||||
/**
|
||||
* "Starts" the widgets. Called at the end of the rendering, this allows
|
||||
* to get a jQuery object referring to the DOM ($element attribute).
|
||||
*/
|
||||
start: function () {
|
||||
this._super();
|
||||
var tmp = document.getElementById(this.element_id);
|
||||
this.$element = tmp ? $(tmp) : null;
|
||||
},
|
||||
/**
|
||||
* "Stops" the widgets. Called when the view destroys itself, this
|
||||
* lets the widgets clean up after themselves.
|
||||
*/
|
||||
stop: function () {
|
||||
var tmp_children = this.children;
|
||||
this.children = [];
|
||||
_.each(tmp_children, function(x) {
|
||||
x.stop();
|
||||
openerp.base.Notification = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
this.$element.notify({
|
||||
speed: 500,
|
||||
expires: 1500
|
||||
});
|
||||
if(this.$element != null) {
|
||||
this.$element.remove();
|
||||
}
|
||||
this.set_parent(null);
|
||||
this._super();
|
||||
},
|
||||
/**
|
||||
* Set the parent of this component, also un-register the previous parent
|
||||
* if there was one.
|
||||
*
|
||||
* @param {openerp.base.BaseWidget} parent The new parent.
|
||||
*/
|
||||
set_parent: function(parent) {
|
||||
if(this.parent) {
|
||||
this.parent.children = _.without(this.parent.children, this);
|
||||
}
|
||||
this.parent = parent;
|
||||
if(this.parent) {
|
||||
parent.children.push(this);
|
||||
}
|
||||
notify: function(title, text) {
|
||||
this.$element.notify('create', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Render the widget. This.template must be defined.
|
||||
* The content of the current object is passed as context to the template.
|
||||
*
|
||||
* @param {object} additional Additional context arguments to pass to the template.
|
||||
*/
|
||||
render: function (additional) {
|
||||
return QWeb.render(this.template, _.extend({}, this, additional != null ? additional : {}));
|
||||
warn: function(title, text) {
|
||||
this.$element.notify('create', 'oe_notification_alert', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.Dialog = openerp.base.BaseWidget.extend({
|
||||
openerp.base.Dialog = openerp.base.OldWidget.extend({
|
||||
dialog_title: "",
|
||||
identifier_prefix: 'dialog',
|
||||
init: function (session, options) {
|
||||
this._super(null, session);
|
||||
init: function (parent, options) {
|
||||
var self = this;
|
||||
this._super(parent);
|
||||
this.options = {
|
||||
modal: true,
|
||||
width: 'auto',
|
||||
|
@ -780,7 +309,10 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({
|
|||
min_height: 0,
|
||||
max_height: '100%',
|
||||
autoOpen: false,
|
||||
buttons: {}
|
||||
buttons: {},
|
||||
beforeClose: function () {
|
||||
self.on_close();
|
||||
}
|
||||
};
|
||||
for (var f in this) {
|
||||
if (f.substr(0, 10) == 'on_button_') {
|
||||
|
@ -843,18 +375,23 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({
|
|||
this.set_options(options);
|
||||
this.$dialog.dialog(this.options).dialog('open');
|
||||
},
|
||||
close: function(options) {
|
||||
close: function() {
|
||||
// Closes the dialog but leave it in a state where it could be opened again.
|
||||
this.$dialog.dialog('close');
|
||||
},
|
||||
on_close: function() {
|
||||
},
|
||||
stop: function () {
|
||||
// Destroy widget
|
||||
this.close();
|
||||
this.$dialog.dialog('destroy');
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.CrashManager = openerp.base.Dialog.extend({
|
||||
identifier_prefix: 'dialog_crash',
|
||||
init: function(session) {
|
||||
this._super(session);
|
||||
init: function(parent) {
|
||||
this._super(parent);
|
||||
this.session.on_rpc_error.add(this.on_rpc_error);
|
||||
},
|
||||
on_button_Ok: function() {
|
||||
|
@ -887,12 +424,9 @@ openerp.base.CrashManager = openerp.base.Dialog.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.Loading = openerp.base.Controller.extend({
|
||||
controller_manifest: {
|
||||
register: ["Loading"]
|
||||
},
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
openerp.base.Loading = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
this.count = 0;
|
||||
this.session.on_rpc_request.add_first(this.on_rpc_event, 1);
|
||||
this.session.on_rpc_response.add_last(this.on_rpc_event, -1);
|
||||
|
@ -909,27 +443,29 @@ openerp.base.Loading = openerp.base.Controller.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.Database = openerp.base.Controller.extend({
|
||||
openerp.base.Database = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.Login = openerp.base.Controller.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
openerp.base.Login = openerp.base.Widget.extend({
|
||||
remember_creditentials: true,
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
this.has_local_storage = typeof(localStorage) != 'undefined';
|
||||
this.selected_db = null;
|
||||
this.selected_login = null;
|
||||
this.selected_password = null;
|
||||
this.remember = false;
|
||||
if (this.has_local_storage && localStorage.getItem('remember_creditentials') === 'true') {
|
||||
this.remember = true;
|
||||
if (this.has_local_storage && this.remember_creditentials) {
|
||||
this.selected_db = localStorage.getItem('last_db_login_success');
|
||||
this.selected_login = localStorage.getItem('last_login_login_success');
|
||||
this.selected_password = localStorage.getItem('last_password_login_success');
|
||||
}
|
||||
if (jQuery.deparam(jQuery.param.querystring()).debug != undefined) {
|
||||
this.selected_db = this.selected_db || "trunk";
|
||||
this.selected_login = this.selected_login || "admin";
|
||||
this.selected_password = this.selected_password || "a";
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
this.rpc("/base/session/get_databases_list", {}, function(result) {
|
||||
this.rpc("/base/database/get_databases_list", {}, function(result) {
|
||||
self.db_list = result.db_list;
|
||||
self.display();
|
||||
}, function() {
|
||||
|
@ -953,22 +489,17 @@ openerp.base.Login = openerp.base.Controller.extend({
|
|||
var db = $e.find("form [name=db]").val();
|
||||
var login = $e.find("form input[name=login]").val();
|
||||
var password = $e.find("form input[name=password]").val();
|
||||
var remember = $e.find("form input[name=remember]").attr('checked');
|
||||
//$e.hide();
|
||||
// Should hide then call callback
|
||||
this.session.session_login(db, login, password, function() {
|
||||
if(self.session.session_is_valid()) {
|
||||
if (self.has_local_storage) {
|
||||
if(remember) {
|
||||
localStorage.setItem('remember_creditentials', 'true');
|
||||
if(self.remember_creditentials) {
|
||||
localStorage.setItem('last_db_login_success', db);
|
||||
localStorage.setItem('last_login_login_success', login);
|
||||
localStorage.setItem('last_password_login_success', password);
|
||||
} else {
|
||||
localStorage.setItem('remember_creditentials', '');
|
||||
localStorage.setItem('last_db_login_success', '');
|
||||
localStorage.setItem('last_login_login_success', '');
|
||||
localStorage.setItem('last_password_login_success', '');
|
||||
}
|
||||
}
|
||||
self.on_login_valid();
|
||||
|
@ -993,9 +524,9 @@ openerp.base.Login = openerp.base.Controller.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.Header = openerp.base.Controller.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
openerp.base.Header = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
},
|
||||
start: function() {
|
||||
this.do_update();
|
||||
|
@ -1007,9 +538,9 @@ openerp.base.Header = openerp.base.Controller.extend({
|
|||
on_logout: function() {}
|
||||
});
|
||||
|
||||
openerp.base.Menu = openerp.base.Controller.extend({
|
||||
init: function(session, element_id, secondary_menu_id) {
|
||||
this._super(session, element_id);
|
||||
openerp.base.Menu = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id, secondary_menu_id) {
|
||||
this._super(parent, element_id);
|
||||
this.secondary_menu_id = secondary_menu_id;
|
||||
this.$secondary_menu = $("#" + secondary_menu_id);
|
||||
this.menu = false;
|
||||
|
@ -1088,45 +619,43 @@ openerp.base.Menu = openerp.base.Controller.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.Homepage = openerp.base.Controller.extend({
|
||||
openerp.base.Homepage = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.Preferences = openerp.base.Controller.extend({
|
||||
openerp.base.Preferences = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.ImportExport = openerp.base.Controller.extend({
|
||||
openerp.base.ImportExport = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.WebClient = openerp.base.Controller.extend({
|
||||
openerp.base.WebClient = openerp.base.Widget.extend({
|
||||
init: function(element_id) {
|
||||
var self = this;
|
||||
this._super(null, element_id);
|
||||
|
||||
QWeb.add_template("xml/base.xml");
|
||||
QWeb.add_template("/base/static/src/xml/base.xml");
|
||||
var params = {};
|
||||
if(jQuery.param != undefined &&
|
||||
jQuery.deparam(jQuery.param.querystring()).kitten != undefined) {
|
||||
if(jQuery.param != undefined && jQuery.deparam(jQuery.param.querystring()).kitten != undefined) {
|
||||
this.$element.addClass("kitten-mode-activated");
|
||||
}
|
||||
this.$element.html(QWeb.render("Interface", params));
|
||||
|
||||
this.session = new openerp.base.Session("oe_errors");
|
||||
this.loading = new openerp.base.Loading(this.session, "oe_loading");
|
||||
this.crashmanager = new openerp.base.CrashManager(this.session);
|
||||
this.session = new openerp.base.Session(this,"oe_errors");
|
||||
this.loading = new openerp.base.Loading(this,"oe_loading");
|
||||
this.crashmanager = new openerp.base.CrashManager(this);
|
||||
this.crashmanager.start(false);
|
||||
|
||||
// Do you autorize this ?
|
||||
openerp.base.Controller.prototype.notification = new openerp.base.Notification("oe_notification");
|
||||
// Do you autorize this ? will be replaced by notify() in controller
|
||||
openerp.base.Widget.prototype.notification = new openerp.base.Notification(this, "oe_notification");
|
||||
|
||||
this.header = new openerp.base.Header(this.session, "oe_header");
|
||||
this.login = new openerp.base.Login(this.session, "oe_login");
|
||||
this.header = new openerp.base.Header(this, "oe_header");
|
||||
this.login = new openerp.base.Login(this, "oe_login");
|
||||
this.header.on_logout.add(this.login.on_logout);
|
||||
|
||||
this.session.on_session_invalid.add(this.login.do_ask_login);
|
||||
this.session.on_session_valid.add_last(this.header.do_update);
|
||||
this.session.on_session_valid.add_last(this.on_logged);
|
||||
|
||||
this.menu = new openerp.base.Menu(this.session, "oe_menu", "oe_secondary_menu");
|
||||
this.menu = new openerp.base.Menu(this, "oe_menu", "oe_secondary_menu");
|
||||
this.menu.on_action.add(this.on_menu_action);
|
||||
},
|
||||
start: function() {
|
||||
|
@ -1137,9 +666,9 @@ openerp.base.WebClient = openerp.base.Controller.extend({
|
|||
this.notification.notify("OpenERP Client", "The openerp client has been initialized.");
|
||||
},
|
||||
on_logged: function() {
|
||||
this.action_manager = new openerp.base.ActionManager(this.session, "oe_app");
|
||||
this.action_manager = new openerp.base.ActionManager(this, "oe_app");
|
||||
this.action_manager.start();
|
||||
|
||||
|
||||
// if using saved actions, load the action and give it to action manager
|
||||
var parameters = jQuery.deparam(jQuery.param.querystring());
|
||||
if(parameters["s_action"] != undefined) {
|
||||
|
|
|
@ -0,0 +1,574 @@
|
|||
/*---------------------------------------------------------
|
||||
* OpenERP controller framework
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
openerp.base.core = function(openerp) {
|
||||
/**
|
||||
* John Resig Class with factory improvement
|
||||
*/
|
||||
(function() {
|
||||
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
// The base Class implementation (does nothing)
|
||||
this.Class = function(){};
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Class.extend = function(prop) {
|
||||
var _super = this.prototype;
|
||||
|
||||
// Instantiate a base class (but only create the instance,
|
||||
// don't run the init constructor)
|
||||
initializing = true;
|
||||
var prototype = new this();
|
||||
initializing = false;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
for (var name in prop) {
|
||||
// Check if we're overwriting an existing function
|
||||
prototype[name] = typeof prop[name] == "function" &&
|
||||
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
|
||||
(function(name, fn){
|
||||
return function() {
|
||||
var tmp = this._super;
|
||||
|
||||
// Add a new ._super() method that is the same method
|
||||
// but on the super-class
|
||||
this._super = _super[name];
|
||||
|
||||
// The method only need to be bound temporarily, so we
|
||||
// remove it when we're done executing
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
|
||||
return ret;
|
||||
};
|
||||
})(name, prop[name]) :
|
||||
prop[name];
|
||||
}
|
||||
|
||||
// The dummy class constructor
|
||||
function Class() {
|
||||
// All construction is actually done in the init method
|
||||
if ( !initializing && this.init ) {
|
||||
var ret = this.init.apply(this, arguments);
|
||||
if (ret) { return ret; }
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.constructor = Class;
|
||||
|
||||
// And make this class extendable
|
||||
Class.extend = arguments.callee;
|
||||
|
||||
return Class;
|
||||
};
|
||||
})();
|
||||
|
||||
// todo change john resig class to keep window clean
|
||||
openerp.base.Class = window.Class
|
||||
|
||||
openerp.base.callback = function(obj, method) {
|
||||
var callback = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var r;
|
||||
for(var i = 0; i < callback.callback_chain.length; i++) {
|
||||
var c = callback.callback_chain[i];
|
||||
if(c.unique) {
|
||||
callback.callback_chain.splice(i, 1);
|
||||
i -= 1;
|
||||
}
|
||||
r = c.callback.apply(c.self, c.args.concat(args));
|
||||
// TODO special value to stop the chain
|
||||
// openerp.base.callback_stop
|
||||
}
|
||||
return r;
|
||||
};
|
||||
callback.callback_chain = [];
|
||||
callback.add = function(f) {
|
||||
if(typeof(f) == 'function') {
|
||||
f = { callback: f, args: Array.prototype.slice.call(arguments, 1) };
|
||||
}
|
||||
f.self = f.self || null;
|
||||
f.args = f.args || [];
|
||||
f.unique = !!f.unique;
|
||||
if(f.position == 'last') {
|
||||
callback.callback_chain.push(f);
|
||||
} else {
|
||||
callback.callback_chain.unshift(f);
|
||||
}
|
||||
return callback;
|
||||
};
|
||||
callback.add_first = function(f) {
|
||||
return callback.add.apply(null,arguments);
|
||||
};
|
||||
callback.add_last = function(f) {
|
||||
return callback.add({
|
||||
callback: f,
|
||||
args: Array.prototype.slice.call(arguments, 1),
|
||||
position: "last"
|
||||
});
|
||||
};
|
||||
|
||||
return callback.add({
|
||||
callback: method,
|
||||
self:obj,
|
||||
args:Array.prototype.slice.call(arguments, 2)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates an inherited class that replaces all the methods by null methods (methods
|
||||
* that does nothing and always return undefined).
|
||||
*
|
||||
* @param {Class} claz
|
||||
* @param {dict} add Additional functions to override.
|
||||
* @return {Class}
|
||||
*/
|
||||
openerp.base.generate_null_object_class = function(claz, add) {
|
||||
var newer = {};
|
||||
var copy_proto = function(prototype) {
|
||||
for (var name in prototype) {
|
||||
if(typeof prototype[name] == "function") {
|
||||
newer[name] = function() {};
|
||||
}
|
||||
}
|
||||
if (prototype.prototype)
|
||||
copy_proto(prototype.prototype);
|
||||
};
|
||||
copy_proto(claz.prototype);
|
||||
newer.init = openerp.base.Widget.prototype.init;
|
||||
var tmpclass = claz.extend(newer);
|
||||
return tmpclass.extend(add || {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Base error for lookup failure
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
openerp.base.NotFound = openerp.base.Class.extend( /** @lends openerp.base.NotFound# */ {
|
||||
});
|
||||
openerp.base.KeyNotFound = openerp.base.NotFound.extend( /** @lends openerp.base.KeyNotFound# */ {
|
||||
/**
|
||||
* Thrown when a key could not be found in a mapping
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.NotFound
|
||||
* @param {String} key the key which could not be found
|
||||
*/
|
||||
init: function (key) {
|
||||
this.key = key;
|
||||
},
|
||||
toString: function () {
|
||||
return "The key " + this.key + " was not found";
|
||||
}
|
||||
});
|
||||
openerp.base.ObjectNotFound = openerp.base.NotFound.extend( /** @lends openerp.base.ObjectNotFound# */ {
|
||||
/**
|
||||
* Thrown when an object path does not designate a valid class or object
|
||||
* in the openerp hierarchy.
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.NotFound
|
||||
* @param {String} path the invalid object path
|
||||
*/
|
||||
init: function (path) {
|
||||
this.path = path;
|
||||
},
|
||||
toString: function () {
|
||||
return "Could not find any object of path " + this.path;
|
||||
}
|
||||
});
|
||||
openerp.base.Registry = openerp.base.Class.extend( /** @lends openerp.base.Registry# */ {
|
||||
/**
|
||||
* Stores a mapping of arbitrary key (strings) to object paths (as strings
|
||||
* as well).
|
||||
*
|
||||
* Resolves those paths at query time in order to always fetch the correct
|
||||
* object, even if those objects have been overloaded/replaced after the
|
||||
* registry was created.
|
||||
*
|
||||
* An object path is simply a dotted name from the openerp root to the
|
||||
* object pointed to (e.g. ``"openerp.base.Session"`` for an OpenERP
|
||||
* session object).
|
||||
*
|
||||
* @constructs
|
||||
* @param {Object} mapping a mapping of keys to object-paths
|
||||
*/
|
||||
init: function (mapping) {
|
||||
this.map = mapping || {};
|
||||
},
|
||||
/**
|
||||
* Retrieves the object matching the provided key string.
|
||||
*
|
||||
* @param {String} key the key to fetch the object for
|
||||
* @returns {Class} the stored class, to initialize
|
||||
*
|
||||
* @throws {openerp.base.KeyNotFound} if the object was not in the mapping
|
||||
* @throws {openerp.base.ObjectNotFound} if the object path was invalid
|
||||
*/
|
||||
get_object: function (key) {
|
||||
var path_string = this.map[key];
|
||||
if (path_string === undefined) {
|
||||
throw new openerp.base.KeyNotFound(key);
|
||||
}
|
||||
|
||||
var object_match = openerp;
|
||||
var path = path_string.split('.');
|
||||
// ignore first section
|
||||
for(var i=1; i<path.length; ++i) {
|
||||
object_match = object_match[path[i]];
|
||||
|
||||
if (object_match === undefined) {
|
||||
throw new openerp.base.ObjectNotFound(path_string);
|
||||
}
|
||||
}
|
||||
return object_match;
|
||||
},
|
||||
/**
|
||||
* Tries a number of keys, and returns the first object matching one of
|
||||
* the keys.
|
||||
*
|
||||
* @param {Array} keys a sequence of keys to fetch the object for
|
||||
* @returns {Class} the first class found matching an object
|
||||
*
|
||||
* @throws {openerp.base.KeyNotFound} if none of the keys was in the mapping
|
||||
* @trows {openerp.base.ObjectNotFound} if a found object path was invalid
|
||||
*/
|
||||
get_any: function (keys) {
|
||||
for (var i=0; i<keys.length; ++i) {
|
||||
try {
|
||||
return this.get_object(keys[i]);
|
||||
} catch (e) {
|
||||
if (e instanceof openerp.base.KeyNotFound) {
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
throw new openerp.base.KeyNotFound(keys.join(','));
|
||||
},
|
||||
/**
|
||||
* Adds a new key and value to the registry.
|
||||
*
|
||||
* This method can be chained.
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {String} object_path fully qualified dotted object path
|
||||
* @returns {openerp.base.Registry} itself
|
||||
*/
|
||||
add: function (key, object_path) {
|
||||
this.map[key] = object_path;
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Creates and returns a copy of the current mapping, with the provided
|
||||
* mapping argument added in (replacing existing keys if needed)
|
||||
*
|
||||
* @param {Object} [mapping={}] a mapping of keys to object-paths
|
||||
*/
|
||||
clone: function (mapping) {
|
||||
return new openerp.base.Registry(
|
||||
_.extend({}, this.map, mapping || {}));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Utility class that any class is allowed to extend to easy common manipulations.
|
||||
*
|
||||
* It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a
|
||||
* logging facility.
|
||||
*/
|
||||
openerp.base.SessionAware = openerp.base.Class.extend({
|
||||
init: function(session) {
|
||||
this.session = session;
|
||||
|
||||
// Transform on_* method into openerp.base.callbacks
|
||||
for (var name in this) {
|
||||
if(typeof(this[name]) == "function") {
|
||||
this[name].debug_name = name;
|
||||
// bind ALL function to this not only on_and _do ?
|
||||
if((/^on_|^do_/).test(name)) {
|
||||
this[name] = openerp.base.callback(this, this[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Performs a JSON-RPC call
|
||||
*
|
||||
* @param {String} url endpoint url
|
||||
* @param {Object} data RPC parameters
|
||||
* @param {Function} success RPC call success callback
|
||||
* @param {Function} error RPC call error callback
|
||||
* @returns {jQuery.Deferred} deferred object for the RPC call
|
||||
*/
|
||||
rpc: function(url, data, success, error) {
|
||||
return this.session.rpc(url, data, success, error);
|
||||
},
|
||||
log: function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var caller = arguments.callee.caller;
|
||||
// TODO add support for line number using
|
||||
// https://github.com/emwendelin/javascript-stacktrace/blob/master/stacktrace.js
|
||||
// args.unshift("" + caller.debug_name);
|
||||
this.on_log.apply(this,args);
|
||||
},
|
||||
on_log: function() {
|
||||
if(window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) {
|
||||
var notify = false;
|
||||
var body = false;
|
||||
if(window.console) {
|
||||
console.log(arguments);
|
||||
} else {
|
||||
body = true;
|
||||
}
|
||||
var a = Array.prototype.slice.call(arguments, 0);
|
||||
for(var i = 0; i < a.length; i++) {
|
||||
var v = a[i]==null ? "null" : a[i].toString();
|
||||
if(i==0) {
|
||||
notify = v.match(/^not/);
|
||||
body = v.match(/^bod/);
|
||||
}
|
||||
if(body) {
|
||||
$('<pre></pre>').text(v).appendTo($('body'));
|
||||
}
|
||||
if(notify && this.notification) {
|
||||
this.notification.notify("Logging:",v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Base class for all visual components. Provides a lot of functionalities helpful
|
||||
* for the management of a part of the DOM.
|
||||
*
|
||||
* Widget handles:
|
||||
* - Rendering with QWeb.
|
||||
* - Life-cycle management and parenting (when a parent is destroyed, all its children are
|
||||
* destroyed too).
|
||||
* - Insertion in DOM.
|
||||
*
|
||||
* Widget also extends SessionAware for ease of use.
|
||||
*
|
||||
* Guide to create implementations of this class:
|
||||
* ==============================================
|
||||
*
|
||||
* Here is a sample child class:
|
||||
*
|
||||
* MyWidget = openerp.base.Widget.extend({
|
||||
* // the name of the QWeb template to use for rendering
|
||||
* template: "MyQWebTemplate",
|
||||
* // identifier prefix, useful to put an obvious one for debugging
|
||||
* identifier_prefix: 'my-id-prefix-',
|
||||
*
|
||||
* init: function(parent) {
|
||||
* this._super(parent);
|
||||
* // stuff that you want to init before the rendering
|
||||
* },
|
||||
* start: function() {
|
||||
* // stuff you want to make after the rendering, `this.$element` holds a value
|
||||
* this.$element.find(".my_button").click(/* an example of event binding * /);
|
||||
*
|
||||
* // if you have some asynchronous operations, it's a good idea to return
|
||||
* // a promise in start()
|
||||
* var promise = this.rpc(...);
|
||||
* return promise;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Now this class can simply be used with the following syntax:
|
||||
*
|
||||
* var my_widget = new MyWidget(this);
|
||||
* my_widget.appendTo($(".some-div"));
|
||||
*
|
||||
* With these two lines, the MyWidget instance was inited, rendered, it was inserted into the
|
||||
* DOM inside the ".some-div" div and its events were binded.
|
||||
*
|
||||
* And of course, when you don't need that widget anymore, just do:
|
||||
*
|
||||
* my_widget.stop();
|
||||
*
|
||||
* That will kill the widget in a clean way and erase its content from the dom.
|
||||
*/
|
||||
openerp.base.Widget = openerp.base.SessionAware.extend({
|
||||
/**
|
||||
* The name of the QWeb template that will be used for rendering. Must be
|
||||
* redefined in subclasses or the default render() method can not be used.
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
template: null,
|
||||
/**
|
||||
* The prefix used to generate an id automatically. Should be redefined in
|
||||
* subclasses. If it is not defined, a generic identifier will be used.
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
identifier_prefix: 'generic-identifier-',
|
||||
/**
|
||||
* @constructs
|
||||
* Construct the widget and set its parent if a parent is given.
|
||||
*
|
||||
* @param {Widget} parent Binds the current instance to the given Widget instance.
|
||||
* When that widget is destroyed by calling stop(), the current instance will be
|
||||
* destroyed too. Can be null.
|
||||
* @param {String} element_id Deprecated. Sets the element_id. Only useful when you want
|
||||
* to bind the current Widget to an already existing part of the DOM, which is not compatible
|
||||
* with the DOM insertion methods provided by the current implementation of Widget. So
|
||||
* for new components this argument should not be provided any more.
|
||||
*/
|
||||
init: function(parent, /** @deprecated */ element_id) {
|
||||
this._super((parent || {}).session);
|
||||
// if given an element_id, try to get the associated DOM element and save
|
||||
// a reference in this.$element. Else just generate a unique identifier.
|
||||
this.element_id = element_id;
|
||||
this.element_id = this.element_id || _.uniqueId(this.identifier_prefix);
|
||||
var tmp = document.getElementById(this.element_id);
|
||||
this.$element = tmp ? $(tmp) : undefined;
|
||||
|
||||
this.widget_parent = parent;
|
||||
this.widget_children = [];
|
||||
if(parent && parent.widget_children) {
|
||||
parent.widget_children.push(this);
|
||||
}
|
||||
// useful to know if the widget was destroyed and should not be used anymore
|
||||
this.widget_is_stopped = false;
|
||||
},
|
||||
/**
|
||||
* Render the current widget and appends it to the given jQuery object or Widget.
|
||||
*
|
||||
* @param target A jQuery object or a Widget instance.
|
||||
*/
|
||||
appendTo: function(target) {
|
||||
var self = this;
|
||||
return this._render_and_insert(function(t) {
|
||||
self.$element.appendTo(t);
|
||||
}, target);
|
||||
},
|
||||
/**
|
||||
* Render the current widget and prepends it to the given jQuery object or Widget.
|
||||
*
|
||||
* @param target A jQuery object or a Widget instance.
|
||||
*/
|
||||
prependTo: function(target) {
|
||||
var self = this;
|
||||
return this._render_and_insert(function(t) {
|
||||
self.$element.prependTo(t);
|
||||
}, target);
|
||||
},
|
||||
/**
|
||||
* Render the current widget and inserts it after to the given jQuery object or Widget.
|
||||
*
|
||||
* @param target A jQuery object or a Widget instance.
|
||||
*/
|
||||
insertAfter: function(target) {
|
||||
var self = this;
|
||||
return this._render_and_insert(function(t) {
|
||||
self.$element.insertAfter(t);
|
||||
}, target);
|
||||
},
|
||||
/**
|
||||
* Render the current widget and inserts it before to the given jQuery object or Widget.
|
||||
*
|
||||
* @param target A jQuery object or a Widget instance.
|
||||
*/
|
||||
insertBefore: function(target) {
|
||||
var self = this;
|
||||
return this._render_and_insert(function(t) {
|
||||
self.$element.insertBefore(t);
|
||||
}, target);
|
||||
},
|
||||
_render_and_insert: function(insertion, target) {
|
||||
var rendered = this.render();
|
||||
this.$element = $(rendered);
|
||||
if (target instanceof openerp.base.Widget)
|
||||
target = target.$element;
|
||||
insertion(target);
|
||||
return this.start();
|
||||
},
|
||||
/**
|
||||
* Renders the widget using QWeb, `this.template` must be defined.
|
||||
* The context given to QWeb contains the "widget" key that references `this`.
|
||||
*
|
||||
* @param {object} additional Additional context arguments to pass to the template.
|
||||
*/
|
||||
render: function (additional) {
|
||||
return QWeb.render(this.template, _.extend({widget: this}, additional || {}));
|
||||
},
|
||||
/**
|
||||
* Method called after rendering. Mostly used to bind actions, perform asynchronous
|
||||
* calls, etc...
|
||||
*
|
||||
* By convention, the method should return a promise to inform the caller when
|
||||
* this widget has been initialized.
|
||||
*
|
||||
* @returns {jQuery.Deferred}
|
||||
*/
|
||||
start: function() {
|
||||
if (!this.$element) {
|
||||
var tmp = document.getElementById(this.element_id);
|
||||
this.$element = tmp ? $(tmp) : undefined;
|
||||
}
|
||||
return $.Deferred().done().promise();
|
||||
},
|
||||
/**
|
||||
* Destroys the current widget, also destory all its children before destroying itself.
|
||||
*/
|
||||
stop: function() {
|
||||
_.each(_.clone(this.widget_children), function(el) {
|
||||
el.stop();
|
||||
});
|
||||
if(this.$element != null) {
|
||||
this.$element.remove();
|
||||
}
|
||||
if (this.widget_parent && this.widget_parent.widget_children) {
|
||||
this.widget_parent.widget_children = _.without(this.widget_parent.widget_children, this);
|
||||
}
|
||||
this.widget_parent = null;
|
||||
this.widget_is_stopped = true;
|
||||
},
|
||||
/**
|
||||
* Inform the action manager to do an action. Of course, this suppose that
|
||||
* the action manager can be found amongst the ancestors of the current widget.
|
||||
* If that's not the case this method will simply return `false`.
|
||||
*/
|
||||
do_action: function(action, on_finished) {
|
||||
if (this.widget_parent) {
|
||||
return this.widget_parent.do_action(action, on_finished);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
rpc: function(url, data, success, error) {
|
||||
var def = $.Deferred().then(success, error);
|
||||
var self = this;
|
||||
this._super(url, data). then(function() {
|
||||
if (!self.widget_is_stopped)
|
||||
def.resolve.apply(def, arguments);
|
||||
}, function() {
|
||||
if (!self.widget_is_stopped)
|
||||
def.reject.apply(def, arguments);
|
||||
});
|
||||
return def.promise();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* For retro compatibility only, the only difference with is that render() uses
|
||||
* directly `this` instead of context with a "widget" key.
|
||||
*/
|
||||
openerp.base.OldWidget = openerp.base.Widget.extend({
|
||||
render: function (additional) {
|
||||
return QWeb.render(this.template, _.extend(_.extend({}, this), additional || {}));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
|
@ -1,7 +1,24 @@
|
|||
|
||||
openerp.base.data = function(openerp) {
|
||||
|
||||
openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.base.DataGroup# */{
|
||||
/**
|
||||
* Serializes the sort criterion array of a dataset into a form which can be
|
||||
* consumed by OpenERP's RPC APIs.
|
||||
*
|
||||
* @param {Array} criterion array of fields, from first to last criteria, prefixed with '-' for reverse sorting
|
||||
* @returns {String} SQL-like sorting string (``ORDER BY``) clause
|
||||
*/
|
||||
openerp.base.serialize_sort = function (criterion) {
|
||||
return _.map(criterion,
|
||||
function (criteria) {
|
||||
if (criteria[0] === '-') {
|
||||
return criteria.slice(1) + ' DESC';
|
||||
}
|
||||
return criteria + ' ASC';
|
||||
}).join(', ');
|
||||
};
|
||||
|
||||
openerp.base.DataGroup = openerp.base.Widget.extend( /** @lends openerp.base.DataGroup# */{
|
||||
/**
|
||||
* Management interface between views and grouped collections of OpenERP
|
||||
* records.
|
||||
|
@ -13,7 +30,7 @@ openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.bas
|
|||
* content of the current grouping level.
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.Controller
|
||||
* @extends openerp.base.Widget
|
||||
*
|
||||
* @param {openerp.base.Session} session Current OpenERP session
|
||||
* @param {String} model name of the model managed by this DataGroup
|
||||
|
@ -22,18 +39,16 @@ openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.bas
|
|||
* @param {Array} group_by sequence of fields by which to group
|
||||
* @param {Number} [level=0] nesting level of the group
|
||||
*/
|
||||
init: function(session, model, domain, context, group_by, level) {
|
||||
init: function(parent, model, domain, context, group_by, level) {
|
||||
this._super(parent, null);
|
||||
if (group_by) {
|
||||
if (group_by.length || context['group_by_no_leaf']) {
|
||||
return new openerp.base.ContainerDataGroup(
|
||||
session, model, domain, context, group_by, level);
|
||||
return new openerp.base.ContainerDataGroup( this, model, domain, context, group_by, level);
|
||||
} else {
|
||||
return new openerp.base.GrouplessDataGroup(
|
||||
session, model, domain, context, level);
|
||||
return new openerp.base.GrouplessDataGroup( this, model, domain, context, level);
|
||||
}
|
||||
}
|
||||
|
||||
this._super(session, null);
|
||||
this.model = model;
|
||||
this.context = context;
|
||||
this.domain = domain;
|
||||
|
@ -42,8 +57,7 @@ openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.bas
|
|||
},
|
||||
cls: 'DataGroup'
|
||||
});
|
||||
openerp.base.ContainerDataGroup = openerp.base.DataGroup.extend(
|
||||
/** @lends openerp.base.ContainerDataGroup# */ {
|
||||
openerp.base.ContainerDataGroup = openerp.base.DataGroup.extend( /** @lends openerp.base.ContainerDataGroup# */ {
|
||||
/**
|
||||
*
|
||||
* @constructs
|
||||
|
@ -56,8 +70,8 @@ openerp.base.ContainerDataGroup = openerp.base.DataGroup.extend(
|
|||
* @param group_by
|
||||
* @param level
|
||||
*/
|
||||
init: function (session, model, domain, context, group_by, level) {
|
||||
this._super(session, model, domain, context, null, level);
|
||||
init: function (parent, model, domain, context, group_by, level) {
|
||||
this._super(parent, model, domain, context, null, level);
|
||||
|
||||
this.group_by = group_by;
|
||||
},
|
||||
|
@ -120,29 +134,26 @@ openerp.base.ContainerDataGroup = openerp.base.DataGroup.extend(
|
|||
aggregates: aggregates
|
||||
};
|
||||
},
|
||||
fetch: function () {
|
||||
fetch: function (fields) {
|
||||
// internal method
|
||||
var d = new $.Deferred();
|
||||
var self = this;
|
||||
|
||||
// disable caching for now, not sure what I should do there
|
||||
if (false && this.groups) {
|
||||
d.resolveWith(this, [this.groups]);
|
||||
} else {
|
||||
this.rpc('/base/group/read', {
|
||||
model: this.model,
|
||||
context: this.context,
|
||||
domain: this.domain,
|
||||
group_by_fields: this.group_by
|
||||
}, function () { }).then(function (response) {
|
||||
var data_groups = _(response.result).map(
|
||||
_.bind(self.transform_group, self));
|
||||
self.groups = data_groups;
|
||||
d.resolveWith(self, [data_groups]);
|
||||
}, function () {
|
||||
d.rejectWith.apply(d, self, [arguments]);
|
||||
});
|
||||
}
|
||||
this.rpc('/base/group/read', {
|
||||
model: this.model,
|
||||
context: this.context,
|
||||
domain: this.domain,
|
||||
fields: _.uniq(this.group_by.concat(fields)),
|
||||
group_by_fields: this.group_by,
|
||||
sort: openerp.base.serialize_sort(this.sort)
|
||||
}, function () { }).then(function (response) {
|
||||
var data_groups = _(response).map(
|
||||
_.bind(self.transform_group, self));
|
||||
self.groups = data_groups;
|
||||
d.resolveWith(self, [data_groups]);
|
||||
}, function () {
|
||||
d.rejectWith.apply(d, [self, arguments]);
|
||||
});
|
||||
return d.promise();
|
||||
},
|
||||
/**
|
||||
|
@ -163,24 +174,27 @@ openerp.base.ContainerDataGroup = openerp.base.DataGroup.extend(
|
|||
* records have for the current ``grouped_on`` field name).
|
||||
* ``aggregates``
|
||||
* a mapping of other aggregation fields provided by ``read_group``
|
||||
*
|
||||
* @param {Array} fields the list of fields to aggregate in each group, can be empty
|
||||
* @param {Function} ifGroups function executed if any group is found (DataGroup.group_by is non-null and non-empty), called with a (potentially empty) list of groups as parameters.
|
||||
* @param {Function} ifRecords function executed if there is no grouping left to perform, called with a DataSet instance as parameter
|
||||
*/
|
||||
list: function (ifGroups, ifRecords) {
|
||||
list: function (fields, ifGroups, ifRecords) {
|
||||
var self = this;
|
||||
this.fetch().then(function (group_records) {
|
||||
this.fetch(fields).then(function (group_records) {
|
||||
ifGroups(_(group_records).map(function (group) {
|
||||
var child_context = _.extend({}, self.context, group.__context);
|
||||
return _.extend(
|
||||
new openerp.base.DataGroup(
|
||||
self.session, self.model, group.__domain,
|
||||
self, self.model, group.__domain,
|
||||
child_context, child_context.group_by,
|
||||
self.level + 1),
|
||||
group);
|
||||
group, {sort: self.sort});
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
openerp.base.GrouplessDataGroup = openerp.base.DataGroup.extend(
|
||||
/** @lends openerp.base.GrouplessDataGroup# */ {
|
||||
openerp.base.GrouplessDataGroup = openerp.base.DataGroup.extend( /** @lends openerp.base.GrouplessDataGroup# */ {
|
||||
/**
|
||||
*
|
||||
* @constructs
|
||||
|
@ -192,16 +206,16 @@ openerp.base.GrouplessDataGroup = openerp.base.DataGroup.extend(
|
|||
* @param context
|
||||
* @param level
|
||||
*/
|
||||
init: function (session, model, domain, context, level) {
|
||||
this._super(session, model, domain, context, null, level);
|
||||
init: function (parent, model, domain, context, level) {
|
||||
this._super(parent, model, domain, context, null, level);
|
||||
},
|
||||
list: function (ifGroups, ifRecords) {
|
||||
ifRecords(new openerp.base.DataSetSearch(this.session, this.model, this.context, this.domain));
|
||||
list: function (fields, ifGroups, ifRecords) {
|
||||
ifRecords(_.extend(
|
||||
new openerp.base.DataSetSearch(this, this.model),
|
||||
{domain: this.domain, context: this.context, _sort: this.sort}));
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.StaticDataGroup = openerp.base.GrouplessDataGroup.extend(
|
||||
/** @lends openerp.base.StaticDataGroup# */ {
|
||||
openerp.base.StaticDataGroup = openerp.base.GrouplessDataGroup.extend( /** @lends openerp.base.StaticDataGroup# */ {
|
||||
/**
|
||||
* A specialization of groupless data groups, relying on a single static
|
||||
* dataset as its records provider.
|
||||
|
@ -213,24 +227,25 @@ openerp.base.StaticDataGroup = openerp.base.GrouplessDataGroup.extend(
|
|||
init: function (dataset) {
|
||||
this.dataset = dataset;
|
||||
},
|
||||
list: function (ifGroups, ifRecords) {
|
||||
list: function (fields, ifGroups, ifRecords) {
|
||||
ifRecords(this.dataset);
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.DataSet# */{
|
||||
openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.DataSet# */{
|
||||
/**
|
||||
* DateaManagement interface between views and the collection of selected
|
||||
* OpenERP records (represents the view's state?)
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.Controller
|
||||
* @extends openerp.base.Widget
|
||||
*
|
||||
* @param {openerp.base.Session} session current OpenERP session
|
||||
* @param {String} model the OpenERP model this dataset will manage
|
||||
*/
|
||||
init: function(session, model, context) {
|
||||
this._super(session);
|
||||
init: function(source_controller, model, context) {
|
||||
// we don't want the dataset to be a child of anything!
|
||||
this._super(null);
|
||||
this.session = source_controller ? source_controller.session : undefined;
|
||||
this.model = model;
|
||||
this.context = context || {};
|
||||
this.index = null;
|
||||
|
@ -276,14 +291,18 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
|||
* Read the indexed record.
|
||||
*/
|
||||
read_index: function (fields, callback) {
|
||||
var def = $.Deferred().then(callback);
|
||||
if (_.isEmpty(this.ids)) {
|
||||
return $.Deferred().reject().promise();
|
||||
def.reject();
|
||||
} else {
|
||||
fields = fields || false;
|
||||
return this.read_ids([this.ids[this.index]], fields, function(records) {
|
||||
callback(records[0]);
|
||||
return this.read_ids([this.ids[this.index]], fields).then(function(records) {
|
||||
def.resolve(records[0]);
|
||||
}, function() {
|
||||
def.reject.apply(def, arguments);
|
||||
});
|
||||
}
|
||||
return def.promise();
|
||||
},
|
||||
default_get: function(fields, callback) {
|
||||
return this.rpc('/base/dataset/default_get', {
|
||||
|
@ -362,26 +381,24 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
|||
return this.context;
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.DataSetStatic = openerp.base.DataSet.extend({
|
||||
init: function(session, model, context, ids) {
|
||||
this._super(session, model, context);
|
||||
init: function(parent, model, context, ids) {
|
||||
this._super(parent, model, context);
|
||||
// all local records
|
||||
this.ids = ids || [];
|
||||
if (this.ids.length) {
|
||||
this.index = 0;
|
||||
}
|
||||
},
|
||||
read_slice: function (fields, offset, limit, callback) {
|
||||
var self = this;
|
||||
offset = offset || 0;
|
||||
var end_pos = limit && limit !== -1 ? offset + limit : undefined;
|
||||
this.read_ids(this.ids.slice(offset, end_pos), fields, callback);
|
||||
return this.read_ids(this.ids.slice(offset, end_pos), fields, callback);
|
||||
},
|
||||
set_ids: function (ids) {
|
||||
this.ids = ids;
|
||||
this.index = this.index <= this.ids.length - 1 ?
|
||||
this.index : (this.ids.length > 0 ? this.length - 1 : 0);
|
||||
if (this.index !== null) {
|
||||
this.index = this.index <= this.ids.length - 1 ?
|
||||
this.index : (this.ids.length > 0 ? this.length - 1 : 0);
|
||||
}
|
||||
},
|
||||
unlink: function(ids) {
|
||||
this.on_unlink(ids);
|
||||
|
@ -391,10 +408,9 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
|
|||
this.set_ids(_.without.apply(null, [this.ids].concat(ids)));
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
||||
init: function(session, model, context, domain) {
|
||||
this._super(session, model, context);
|
||||
init: function(parent, model, context, domain) {
|
||||
this._super(parent, model, context);
|
||||
this.domain = domain || [];
|
||||
this._sort = [];
|
||||
this.offset = 0;
|
||||
|
@ -413,7 +429,7 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
|||
// return read_ids(ids.slice(start,start+limit),fields,callback)
|
||||
}
|
||||
}
|
||||
this.rpc('/base/dataset/search_read', {
|
||||
return this.rpc('/base/dataset/search_read', {
|
||||
model: this.model,
|
||||
fields: fields,
|
||||
domain: this.domain,
|
||||
|
@ -421,13 +437,12 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
|||
sort: this.sort(),
|
||||
offset: offset,
|
||||
limit: limit
|
||||
}, function (records) {
|
||||
self.ids.splice(0, self.ids.length);
|
||||
}, function (result) {
|
||||
self.ids = result.ids;
|
||||
self.offset = offset;
|
||||
for (var i=0; i < records.length; i++ ) {
|
||||
self.ids.push(records[i].id);
|
||||
if (callback) {
|
||||
callback(result.records);
|
||||
}
|
||||
callback(records);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -445,16 +460,12 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
|||
*/
|
||||
sort: function (field, force_reverse) {
|
||||
if (!field) {
|
||||
return _.map(this._sort, function (criteria) {
|
||||
if (criteria[0] === '-') {
|
||||
return criteria.slice(1) + ' DESC';
|
||||
}
|
||||
return criteria + ' ASC';
|
||||
}).join(', ');
|
||||
return openerp.base.serialize_sort(this._sort);
|
||||
}
|
||||
|
||||
var reverse = force_reverse || (this._sort[0] === field);
|
||||
this._sort = _.without(this._sort, field, '-' + field);
|
||||
this._sort.splice.apply(
|
||||
this._sort, [0, this._sort.length].concat(
|
||||
_.without(this._sort, field, '-' + field)));
|
||||
|
||||
this._sort.unshift((reverse ? '-' : '') + field);
|
||||
return undefined;
|
||||
|
@ -463,14 +474,15 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
|||
var self = this;
|
||||
return this._super(ids, function(result) {
|
||||
self.ids = _.without.apply(_, [self.ids].concat(ids));
|
||||
self.index = self.index <= self.ids.length - 1 ?
|
||||
self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
|
||||
if (this.index !== null) {
|
||||
self.index = self.index <= self.ids.length - 1 ?
|
||||
self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
|
||||
}
|
||||
if (callback)
|
||||
callback(result);
|
||||
}, error_callback);
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.BufferedDataSet = openerp.base.DataSetStatic.extend({
|
||||
virtual_id_prefix: "one2many_v_id_",
|
||||
virtual_id_regex: /one2many_v_id_.*/,
|
||||
|
@ -483,26 +495,34 @@ openerp.base.BufferedDataSet = openerp.base.DataSetStatic.extend({
|
|||
var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data};
|
||||
this.to_create.push(cached);
|
||||
this.cache.push(cached);
|
||||
this.on_change();
|
||||
var to_return = $.Deferred().then(callback);
|
||||
setTimeout(function() {to_return.resolve({result: cached.id});}, 0);
|
||||
to_return.resolve({result: cached.id});
|
||||
return to_return.promise();
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
var self = this;
|
||||
var record = _.detect(this.to_create, function(x) {return x.id === id;});
|
||||
record = record || _.detect(this.to_write, function(x) {return x.id === id;});
|
||||
var dirty = false;
|
||||
if (record) {
|
||||
for (k in data) {
|
||||
if (record.values[k] === undefined || record.values[k] !== data[k]) {
|
||||
dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$.extend(record.values, data);
|
||||
} else {
|
||||
dirty = true;
|
||||
record = {id: id, values: data};
|
||||
self.to_write.push(record);
|
||||
}
|
||||
var cached = _.detect(this.cache, function(x) {return x.id === id;});
|
||||
$.extend(cached.values, record.values);
|
||||
this.on_change();
|
||||
if (dirty)
|
||||
this.on_change();
|
||||
var to_return = $.Deferred().then(callback);
|
||||
setTimeout(function () {to_return.resolve({result: true});}, 0);
|
||||
to_return.resolve({result: true});
|
||||
return to_return.promise();
|
||||
},
|
||||
unlink: function(ids, callback, error_callback) {
|
||||
|
@ -576,7 +596,6 @@ openerp.base.BufferedDataSet = openerp.base.DataSetStatic.extend({
|
|||
return completion.promise();
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.ReadOnlyDataSetSearch = openerp.base.DataSetSearch.extend({
|
||||
create: function(data, callback, error_callback) {
|
||||
this.on_create(data);
|
||||
|
@ -586,12 +605,12 @@ openerp.base.ReadOnlyDataSetSearch = openerp.base.DataSetSearch.extend({
|
|||
},
|
||||
on_create: function(data) {},
|
||||
write: function (id, data, callback) {
|
||||
this.on_write(id);
|
||||
this.on_write(id, data);
|
||||
var to_return = $.Deferred().then(callback);
|
||||
setTimeout(function () {to_return.resolve({"result": true});}, 0);
|
||||
return to_return.promise();
|
||||
},
|
||||
on_write: function(id) {},
|
||||
on_write: function(id, data) {},
|
||||
unlink: function(ids, callback, error_callback) {
|
||||
this.on_unlink(ids);
|
||||
var to_return = $.Deferred().then(callback);
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
openerp.base.data_export = function(openerp) {
|
||||
openerp.base.DataExport = openerp.base.Dialog.extend({
|
||||
init: function(parent, dataset) {
|
||||
this._super(parent);
|
||||
this.dataset = dataset;
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
self._super(false);
|
||||
self.template = 'ExportTreeView';
|
||||
self.dialog_title = "Export Data";
|
||||
self.open({
|
||||
modal: true,
|
||||
width: '55%',
|
||||
height: 'auto',
|
||||
position: 'top',
|
||||
buttons : {
|
||||
"Close" : function() {
|
||||
self.close();
|
||||
},
|
||||
"Export To File" : function() {
|
||||
self.on_click_export_data();
|
||||
}
|
||||
},
|
||||
close: function(event, ui){ self.close();}
|
||||
});
|
||||
self.on_show_exists_export_list();
|
||||
self.$element.removeClass('ui-dialog-content ui-widget-content');
|
||||
self.$element.find('#add_field').click(function() {
|
||||
if ($('#field-tree-structure tr.ui-selected')) {
|
||||
var fld = self.$element.find('#field-tree-structure tr.ui-selected').find('a');
|
||||
for (var i = 0; i < fld.length; i++) {
|
||||
var id = $(fld[i]).attr('id').split('-')[1];
|
||||
var string = $(fld[i]).attr('string');
|
||||
self.add_field(id, string);
|
||||
}
|
||||
self.$element.find('#field-tree-structure tr').removeClass('ui-selected');
|
||||
}
|
||||
});
|
||||
self.$element.find('#remove_field').click(function() {
|
||||
self.$element.find('#fields_list option:selected').remove();
|
||||
});
|
||||
self.$element.find('#remove_all_field').click(function() {
|
||||
self.$element.find('#fields_list option').remove();
|
||||
});
|
||||
self.$element.find('#export_new_list').click(function() {
|
||||
self.on_show_save_list();
|
||||
});
|
||||
var import_comp = self.$element.find('#import_compat option:selected').val(),
|
||||
params = {
|
||||
import_compat: parseInt(import_comp)
|
||||
};
|
||||
self.rpc('/base/export/get_fields', { model: self.dataset.model, params: params }, self.on_show_data);
|
||||
|
||||
self.$element.find('#import_compat').change(function() {
|
||||
self.$element.find('#fields_list option').remove();
|
||||
self.$element.find('#field-tree-structure').remove();
|
||||
var import_comp = self.$element.find("#import_compat option:selected").val();
|
||||
if (import_comp) {
|
||||
var params = {
|
||||
import_compat: parseInt(import_comp)
|
||||
}
|
||||
self.rpc("/base/export/get_fields", { model: self.dataset.model, params: params}, self.on_show_data);
|
||||
}
|
||||
});
|
||||
},
|
||||
on_show_exists_export_list: function() {
|
||||
var self = this;
|
||||
if (self.$element.find('#saved_export_list').is(':hidden')) {
|
||||
self.$element.find('#ExistsExportList').show();
|
||||
} else {
|
||||
this.rpc('/base/export/exist_export_lists', { 'model': this.dataset.model}, function(export_list) {
|
||||
if (export_list.length) {
|
||||
self.$element.find('#ExistsExportList').append(QWeb.render('Exists.ExportList', {'existing_exports': export_list}));
|
||||
self.$element.find('#saved_export_list').change(function() {
|
||||
self.$element.find('#fields_list option').remove();
|
||||
var export_id = self.$element.find('#saved_export_list option:selected').val();
|
||||
if (export_id) {
|
||||
self.rpc('/base/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}, self.do_load_export_field);
|
||||
}
|
||||
});
|
||||
self.$element.find('#delete_export_list').click(function() {
|
||||
var select_exp = self.$element.find('#saved_export_list option:selected');
|
||||
if (select_exp.val()) {
|
||||
self.rpc('/base/export/delete_export', { export_id: parseInt(select_exp.val())}, {});
|
||||
select_exp.remove();
|
||||
if (self.$element.find('#saved_export_list option').length <= 1) {
|
||||
self.$element.find('#ExistsExportList').hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
do_load_export_field: function(field_list) {
|
||||
var export_node = this.$element.find("#fields_list");
|
||||
for (var key in field_list) {
|
||||
export_node.append(new Option(field_list[key], key));
|
||||
}
|
||||
},
|
||||
on_show_save_list: function() {
|
||||
var self = this;
|
||||
var current_node = self.$element.find("#savenewlist");
|
||||
if (!(current_node.find("label")).length) {
|
||||
current_node.append(QWeb.render('ExportNewList'));
|
||||
current_node.find("#add_export_list").click(function() {
|
||||
var value = current_node.find("#savelist_name").val();
|
||||
if (value) {
|
||||
self.do_save_export_list(value);
|
||||
} else {
|
||||
alert("Pleae Enter Save Field List Name");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (current_node.is(':hidden')) {
|
||||
current_node.show();
|
||||
current_node.find("#savelist_name").val("");
|
||||
} else {
|
||||
current_node.hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
do_save_export_list: function(value) {
|
||||
var self = this;
|
||||
var export_field = self.get_fields();
|
||||
if (export_field.length) {
|
||||
self.rpc("/base/export/save_export_lists", {"model": self.dataset.model, "name":value, "field_list":export_field}, function(exp_id) {
|
||||
if (exp_id) {
|
||||
if (self.$element.find("#saved_export_list").length > 0) {
|
||||
self.$element.find("#saved_export_list").append(new Option(value, exp_id));
|
||||
} else {
|
||||
self.on_show_exists_export_list();
|
||||
}
|
||||
if (self.$element.find("#saved_export_list").is(":hidden")) {
|
||||
self.on_show_exists_export_list();
|
||||
}
|
||||
}
|
||||
});
|
||||
self.on_show_save_list();
|
||||
self.$element.find("#fields_list option").remove();
|
||||
}
|
||||
},
|
||||
on_click: function(id, result) {
|
||||
var self = this;
|
||||
self.field_id = id.split("-")[1];
|
||||
var is_loaded = 0;
|
||||
_.each(result, function(record) {
|
||||
if (record['id'] == self.field_id && (record['children']).length >= 1) {
|
||||
var model = record['params']['model'],
|
||||
prefix = record['params']['prefix'],
|
||||
name = record['params']['name'];
|
||||
$(record['children']).each(function(e, childid) {
|
||||
if (self.$element.find("tr[id='treerow-" + childid + "']").length > 0) {
|
||||
if (self.$element.find("tr[id='treerow-" + childid + "']").is(':hidden')) {
|
||||
is_loaded = -1;
|
||||
} else {
|
||||
is_loaded++;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (is_loaded == 0) {
|
||||
if (self.$element.find("tr[id='treerow-" + self.field_id +"']").find('img').attr('src') === '/base/static/src/img/expand.gif') {
|
||||
if (model) {
|
||||
var import_comp = self.$element.find("#import_compat option:selected").val();
|
||||
var params = {
|
||||
import_compat: parseInt(import_comp),
|
||||
parent_field_type : record['field_type']
|
||||
}
|
||||
self.rpc("/base/export/get_fields", {
|
||||
model: model,
|
||||
prefix: prefix,
|
||||
name: name,
|
||||
field_parent : self.field_id,
|
||||
params: params
|
||||
}, function(results) {
|
||||
self.on_show_data(results);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (is_loaded > 0) {
|
||||
self.showcontent(self.field_id, true);
|
||||
} else {
|
||||
self.showcontent(self.field_id, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
on_show_data: function(result) {
|
||||
var self = this;
|
||||
var imp_cmpt = parseInt(self.$element.find("#import_compat option:selected").val());
|
||||
var current_tr = self.$element.find("tr[id='treerow-" + self.field_id + "']");
|
||||
if (current_tr.length >= 1) {
|
||||
current_tr.find('img').attr('src','/base/static/src/img/collapse.gif');
|
||||
current_tr.after(QWeb.render('ExportTreeView-Secondary.children', {'fields': result}));
|
||||
} else {
|
||||
self.$element.find('#left_field_panel').append(QWeb.render('ExportTreeView-Secondary', {'fields': result}));
|
||||
}
|
||||
_.each(result, function(record) {
|
||||
if ((record.field_type == "one2many") && imp_cmpt) {
|
||||
var o2m_fld = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
|
||||
o2m_fld.addClass("oe_export_readonlyfield");
|
||||
}
|
||||
if ((record.required == true) || record.required == "True") {
|
||||
var required_fld = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
|
||||
required_fld.addClass("oe_export_requiredfield");
|
||||
}
|
||||
self.$element.find("img[id='parentimg-" + record.id +"']").click(function() {
|
||||
self.on_click(this.id, result);
|
||||
});
|
||||
|
||||
self.$element.find("tr[id='treerow-" + record.id + "']").click(function(e) {
|
||||
if (e.shiftKey == true) {
|
||||
var frst_click, scnd_click = '';
|
||||
if (self.row_index == 0) {
|
||||
self.row_index = this.rowIndex;
|
||||
frst_click = self.$element.find("tr[id^='treerow-']")[self.row_index-1];
|
||||
$(frst_click).addClass("ui-selected");
|
||||
} else {
|
||||
if (this.rowIndex >=self.row_index) {
|
||||
for (i = (self.row_index-1); i < this.rowIndex; i++) {
|
||||
scnd_click = self.$element.find("tr[id^='treerow-']")[i];
|
||||
if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
|
||||
$(scnd_click).addClass("ui-selected");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = (self.row_index-1); i >= (this.rowIndex-1); i--) {
|
||||
scnd_click = self.$element.find("tr[id^='treerow-']")[i];
|
||||
if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
|
||||
$(scnd_click).addClass("ui-selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.row_index = this.rowIndex;
|
||||
|
||||
self.$element.find("tr[id='treerow-" + record.id + "']").keyup(function(e) {
|
||||
self.row_index = 0;
|
||||
});
|
||||
var o2m_selection = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
|
||||
if ($(o2m_selection).hasClass("oe_export_readonlyfield")) {
|
||||
return false;
|
||||
}
|
||||
var selected = self.$element.find("tr.ui-selected");
|
||||
if ($(this).hasClass("ui-selected") && (e.ctrlKey == true)) {
|
||||
$(this).find('a').blur();
|
||||
$(this).removeClass("ui-selected");
|
||||
} else if ($(this).hasClass("ui-selected") && (e.ctrlKey == false) && (e.shiftKey == false)) {
|
||||
selected.find('a').blur();
|
||||
selected.removeClass("ui-selected");
|
||||
$(this).find('a').focus();
|
||||
$(this).addClass("ui-selected");
|
||||
} else if (!$(this).hasClass("ui-selected") && (e.ctrlKey == false) && (e.shiftKey == false)) {
|
||||
selected.find('a').blur();
|
||||
selected.removeClass("ui-selected");
|
||||
$(this).find('a').focus();
|
||||
$(this).addClass("ui-selected");
|
||||
} else if (!$(this).hasClass("ui-selected") && (e.ctrlKey == true)) {
|
||||
$(this).find('a').focus();
|
||||
$(this).addClass("ui-selected");
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
self.$element.find("tr[id='treerow-" + record.id + "']").keydown(function(e) {
|
||||
var keyCode = e.keyCode || e.which;
|
||||
arrow = {left: 37, up: 38, right: 39, down: 40 };
|
||||
switch (keyCode) {
|
||||
case arrow.left:
|
||||
if ($(this).find('img').attr('src') === '/base/static/src/img/collapse.gif') {
|
||||
self.on_click(this.id, result);
|
||||
}
|
||||
break;
|
||||
case arrow.up:
|
||||
var elem = this;
|
||||
$(elem).removeClass("ui-selected");
|
||||
while ($(elem).prev().is(":visible") == false) {
|
||||
elem = $(elem).prev();
|
||||
}
|
||||
if (!$(elem).prev().find('#tree-column').hasClass("oe_export_readonlyfield")) {
|
||||
$(elem).prev().addClass("ui-selected");
|
||||
}
|
||||
$(elem).prev().find('a').focus();
|
||||
break;
|
||||
case arrow.right:
|
||||
if ($(this).find('img').attr('src') == '/base/static/src/img/expand.gif') {
|
||||
self.on_click(this.id, result);
|
||||
}
|
||||
break;
|
||||
case arrow.down:
|
||||
var elem = this;
|
||||
$(elem).removeClass("ui-selected");
|
||||
while($(elem).next().is(":visible") == false) {
|
||||
elem = $(elem).next();
|
||||
}
|
||||
if (!$(elem).next().find('#tree-column').hasClass("oe_export_readonlyfield")) {
|
||||
$(elem).next().addClass("ui-selected");
|
||||
}
|
||||
$(elem).next().find('a').focus();
|
||||
break;
|
||||
}
|
||||
});
|
||||
self.$element.find("tr[id='treerow-" + record.id + "']").dblclick(function(e) {
|
||||
var $o2m_selection = self.$element.find("tr[id^='treerow-" + record.id + "']").find('#tree-column');
|
||||
if (!$o2m_selection.hasClass("oe_export_readonlyfield")) {
|
||||
var field_id = $(this).find("a").attr("id");
|
||||
if (field_id) {
|
||||
self.add_field(field_id.split('-')[1], $(this).find("a").attr("string"));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
self.$element.find('#fields_list').mouseover(function(event) {
|
||||
if (event.relatedTarget) {
|
||||
if (event.relatedTarget.attributes['id'] && event.relatedTarget.attributes['string']) {
|
||||
var field_id = event.relatedTarget.attributes["id"]["value"];
|
||||
if (field_id && field_id.split("-")[0] === 'export') {
|
||||
if (!self.$element.find("tr[id='treerow-" + field_id.split("-")[1] + "']").find('#tree-column').hasClass("oe_export_readonlyfield")) {
|
||||
self.add_field(field_id.split("-")[1], event.relatedTarget.attributes["string"]["value"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
showcontent: function(id, flag) {
|
||||
// show & hide the contents
|
||||
var first_child = this.$element.find("tr[id='treerow-" + id + "']").find('img');
|
||||
if (flag) {
|
||||
first_child.attr('src', '/base/static/src/img/expand.gif');
|
||||
}
|
||||
else {
|
||||
first_child.attr('src', '/base/static/src/img/collapse.gif');
|
||||
}
|
||||
var child_field = this.$element.find("tr[id^='treerow-" + id +"/']");
|
||||
var child_len = (id.split("/")).length + 1;
|
||||
for (var i = 0; i < child_field.length; i++) {
|
||||
if (flag) {
|
||||
$(child_field[i]).hide();
|
||||
} else {
|
||||
if (child_len == (child_field[i].id.split("/")).length) {
|
||||
if ($(child_field[i]).find('img').attr('src') == '/base/static/src/img/collapse.gif') {
|
||||
$(child_field[i]).find('img').attr('src', '/base/static/src/img/expand.gif');
|
||||
}
|
||||
$(child_field[i]).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
add_field: function(field_id, string) {
|
||||
var field_list = this.$element.find('#fields_list');
|
||||
if (this.$element.find("#fields_list option[value='" + field_id + "']") && !this.$element.find("#fields_list option[value='" + field_id + "']").length) {
|
||||
field_list.append(new Option(string, field_id));
|
||||
}
|
||||
},
|
||||
get_fields: function() {
|
||||
var export_field = [];
|
||||
this.$element.find("#fields_list option").each(function() {
|
||||
export_field.push($(this).val());
|
||||
});
|
||||
if (!export_field.length) {
|
||||
alert('Please select fields to save export list...');
|
||||
}
|
||||
return export_field;
|
||||
},
|
||||
on_click_export_data: function() {
|
||||
var self = this;
|
||||
var export_field = {};
|
||||
var flag = true;
|
||||
self.$element.find("#fields_list option").each(function() {
|
||||
export_field[$(this).val()] = $(this).text();
|
||||
flag = false;
|
||||
});
|
||||
if (flag) {
|
||||
alert('Please select fields to export...');
|
||||
return;
|
||||
}
|
||||
|
||||
var import_comp = self.$element.find("#import_compat option:selected").val(),
|
||||
export_format = self.$element.find("#export_format").val();
|
||||
|
||||
self.rpc("/base/export/export_data", {
|
||||
model: self.dataset.model,
|
||||
fields: export_field,
|
||||
ids: self.dataset.ids,
|
||||
domain: self.dataset.domain,
|
||||
import_compat: parseInt(import_comp),
|
||||
export_format: export_format
|
||||
}, function(data) {
|
||||
window.location = "data:text/csv/excel;charset=utf8," + data;
|
||||
self.close();
|
||||
});
|
||||
},
|
||||
close: function() {
|
||||
$(this.$dialog).remove();
|
||||
this._super();
|
||||
}
|
||||
});
|
||||
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -103,80 +103,106 @@ openerp.base.list.editable = function (openerp) {
|
|||
* Checks if a record is being edited, and if so cancels it
|
||||
*/
|
||||
cancel_pending_edition: function () {
|
||||
var self = this, cancelled = $.Deferred();
|
||||
if (!this.edition) {
|
||||
return;
|
||||
cancelled.resolve();
|
||||
return cancelled.promise();
|
||||
}
|
||||
|
||||
if (this.edition_index !== null) {
|
||||
this.reload_record(this.edition_index);
|
||||
this.reload_record(this.edition_index, true).then(function () {
|
||||
cancelled.resolve();
|
||||
});
|
||||
} else {
|
||||
cancelled.resolve();
|
||||
}
|
||||
this.edition_form.stop();
|
||||
this.edition_form.$element.remove();
|
||||
delete this.edition_form;
|
||||
delete this.edition_index;
|
||||
delete this.edition;
|
||||
cancelled.then(function () {
|
||||
self.edition_form.stop();
|
||||
self.edition_form.$element.remove();
|
||||
delete self.edition_form;
|
||||
delete self.edition_index;
|
||||
delete self.edition;
|
||||
});
|
||||
return cancelled.promise();
|
||||
},
|
||||
/**
|
||||
* Adapts this list's view description to be suitable to the inner form view of a row being edited.
|
||||
*
|
||||
* @returns {Object} fields_view_get's view section suitable for putting into form view of editable rows.
|
||||
*/
|
||||
get_form_fields_view: function () {
|
||||
// deep copy of view
|
||||
var view = $.extend(true, {}, this.group.view.fields_view);
|
||||
_(view.arch.children).each(function (widget) {
|
||||
widget.attrs.nolabel = true;
|
||||
if (widget.tag === 'button') {
|
||||
delete widget.attrs.string;
|
||||
}
|
||||
});
|
||||
view.arch.attrs.col = 2 * view.arch.children.length;
|
||||
return view;
|
||||
},
|
||||
render_row_as_form: function (row) {
|
||||
this.cancel_pending_edition();
|
||||
|
||||
var self = this;
|
||||
var $new_row = $('<tr>', {
|
||||
id: _.uniqueId('oe-editable-row-'),
|
||||
'class': $(row).attr('class'),
|
||||
click: function (e) {e.stopPropagation();}
|
||||
})
|
||||
.delegate('button.oe-edit-row-save', 'click', function () {
|
||||
self.save_row();
|
||||
})
|
||||
.delegate('button.oe-edit-row-cancel', 'click', function () {
|
||||
self.cancel_edition();
|
||||
})
|
||||
.delegate('button', 'keyup', function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
})
|
||||
.keyup(function (e) {
|
||||
switch (e.which) {
|
||||
case KEY_RETURN:
|
||||
self.save_row(true);
|
||||
break;
|
||||
case KEY_ESCAPE:
|
||||
self.cancel_edition();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (row) {
|
||||
$new_row.replaceAll(row);
|
||||
} else if (this.options.editable === 'top') {
|
||||
this.$current.prepend($new_row);
|
||||
} else if (this.options.editable) {
|
||||
this.$current.append($new_row);
|
||||
}
|
||||
this.edition = true;
|
||||
this.edition_index = this.dataset.index;
|
||||
this.edition_form = _.extend(new openerp.base.FormView(
|
||||
null, this.group.view.session, $new_row.attr('id'),
|
||||
this.dataset, false), {
|
||||
template: 'ListView.row.form',
|
||||
registry: openerp.base.list.form.widgets
|
||||
});
|
||||
$.when(this.edition_form.on_loaded({fields_view: this.get_fields_view()})).then(function () {
|
||||
// put in $.when just in case FormView.on_loaded becomes asynchronous
|
||||
$new_row.find('td')
|
||||
.addClass('oe-field-cell')
|
||||
.removeAttr('width')
|
||||
.end()
|
||||
.find('td:first').removeClass('oe-field-cell').end()
|
||||
.find('td:last').removeClass('oe-field-cell').end();
|
||||
// pad in case of groupby
|
||||
_(self.columns).each(function (column) {
|
||||
if (column.meta) {
|
||||
$new_row.prepend('<td>');
|
||||
}
|
||||
this.cancel_pending_edition().then(function () {
|
||||
var $new_row = $('<tr>', {
|
||||
id: _.uniqueId('oe-editable-row-'),
|
||||
'class': $(row).attr('class'),
|
||||
click: function (e) {e.stopPropagation();}
|
||||
})
|
||||
.delegate('button.oe-edit-row-save', 'click', function () {
|
||||
self.save_row();
|
||||
})
|
||||
.delegate('button.oe-edit-row-cancel', 'click', function () {
|
||||
self.cancel_edition();
|
||||
})
|
||||
.delegate('button', 'keyup', function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
})
|
||||
.keyup(function (e) {
|
||||
switch (e.which) {
|
||||
case KEY_RETURN:
|
||||
self.save_row(true);
|
||||
break;
|
||||
case KEY_ESCAPE:
|
||||
self.cancel_edition();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (row) {
|
||||
$new_row.replaceAll(row);
|
||||
} else if (self.options.editable === 'top') {
|
||||
self.$current.prepend($new_row);
|
||||
} else if (self.options.editable) {
|
||||
self.$current.append($new_row);
|
||||
}
|
||||
self.edition = true;
|
||||
self.edition_index = self.dataset.index;
|
||||
self.edition_form = _.extend(new openerp.base.FormView(
|
||||
null, self.group.view.session, $new_row.attr('id'),
|
||||
self.dataset, false), {
|
||||
template: 'ListView.row.form',
|
||||
registry: openerp.base.list.form.widgets
|
||||
});
|
||||
$.when(self.edition_form.on_loaded({fields_view: self.get_form_fields_view()})).then(function () {
|
||||
// put in $.when just in case FormView.on_loaded becomes asynchronous
|
||||
$new_row.find('td')
|
||||
.addClass('oe-field-cell')
|
||||
.removeAttr('width')
|
||||
.end()
|
||||
.find('td:first').removeClass('oe-field-cell').end()
|
||||
.find('td:last').removeClass('oe-field-cell').end();
|
||||
// pad in case of groupby
|
||||
_(self.columns).each(function (column) {
|
||||
if (column.meta) {
|
||||
$new_row.prepend('<td>');
|
||||
}
|
||||
});
|
||||
|
||||
self.edition_form.do_show();
|
||||
self.edition_form.do_show();
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -188,12 +214,7 @@ openerp.base.list.editable = function (openerp) {
|
|||
save_row: function (edit_next) {
|
||||
var self = this;
|
||||
this.edition_form.do_save(function (result) {
|
||||
self.reload_record(self.dataset.index, true).then(function () {
|
||||
self.edition_form.stop();
|
||||
delete self.edition_form;
|
||||
delete self.edition_index;
|
||||
delete self.edition;
|
||||
|
||||
self.cancel_pending_edition().then(function () {
|
||||
$(self).trigger('saved', [self.dataset]);
|
||||
if (!edit_next) {
|
||||
return;
|
||||
|
@ -230,7 +251,12 @@ openerp.base.list.editable = function (openerp) {
|
|||
this.render_row_as_form();
|
||||
}
|
||||
});
|
||||
openerp.base.list = {form: {}};
|
||||
if (!openerp.base.list) {
|
||||
openerp.base.list = {};
|
||||
}
|
||||
if (!openerp.base.list.form) {
|
||||
openerp.base.list.form = {};
|
||||
}
|
||||
openerp.base.list.form.WidgetFrame = openerp.base.form.WidgetFrame.extend({
|
||||
template: 'ListView.row.frame'
|
||||
});
|
||||
|
@ -251,10 +277,12 @@ openerp.base.list.editable = function (openerp) {
|
|||
openerp.base.list.form[key] = (form_widgets.get_object(key)).extend({
|
||||
update_dom: function () {
|
||||
this.$element.children().css('visibility', '');
|
||||
if (this.invisible && this.node.attrs.invisible !== '1') {
|
||||
if (this.invisible) {
|
||||
this.$element.children().css('visibility', 'hidden');
|
||||
} else {
|
||||
this.invisible = !!this.modifiers.tree_invisible;
|
||||
this._super();
|
||||
this.invisible = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,63 @@
|
|||
openerp.base.list = function (openerp) {
|
||||
openerp.base.views.add('list', 'openerp.base.ListView');
|
||||
openerp.base.list = {
|
||||
/**
|
||||
* Formats the rendring of a given value based on its field type
|
||||
*
|
||||
* @param {Object} row_data record whose values should be displayed in the cell
|
||||
* @param {Object} column column descriptor
|
||||
* @param {"button"|"field"} column.tag base control type
|
||||
* @param {String} column.type widget type for a field control
|
||||
* @param {String} [column.string] button label
|
||||
* @param {String} [column.icon] button icon
|
||||
* @param {String} [value_if_empty=''] what to display if the field's value is ``false``
|
||||
*/
|
||||
render_cell: function (row_data, column, value_if_empty) {
|
||||
var attrs = column.modifiers_for(row_data);
|
||||
if (attrs.invisible) { return ''; }
|
||||
if (column.tag === 'button') {
|
||||
return [
|
||||
'<button type="button" title="', column.string || '', '">',
|
||||
'<img src="/base/static/src/img/icons/', column.icon, '.png"',
|
||||
' alt="', column.string || '', '"/>',
|
||||
'</button>'
|
||||
].join('')
|
||||
}
|
||||
|
||||
var value = row_data[column.id].value;
|
||||
|
||||
// If NaN value, display as with a `false` (empty cell)
|
||||
if (typeof value === 'number' && isNaN(value)) {
|
||||
value = false;
|
||||
}
|
||||
switch (value) {
|
||||
case false:
|
||||
case Infinity:
|
||||
case -Infinity:
|
||||
return value_if_empty === undefined ? '' : value_if_empty;
|
||||
}
|
||||
switch (column.widget || column.type) {
|
||||
case 'integer':
|
||||
return _.sprintf('%d', value);
|
||||
case 'float':
|
||||
var precision = column.digits ? column.digits[1] : 2;
|
||||
return _.sprintf('%.' + precision + 'f', value);
|
||||
case 'float_time':
|
||||
return _.sprintf("%02d:%02d",
|
||||
Math.floor(value),
|
||||
Math.round((value % 1) * 60));
|
||||
case 'progressbar':
|
||||
return _.sprintf(
|
||||
'<progress value="%.2f" max="100.0">%.2f%%</progress>',
|
||||
value, value);
|
||||
case 'many2one':
|
||||
// name_get value format
|
||||
return value[1];
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
};
|
||||
openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListView# */ {
|
||||
defaults: {
|
||||
// records can be selected one by one
|
||||
|
@ -42,9 +100,10 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
*
|
||||
* @borrows openerp.base.ActionExecutor#execute_action as #execute_action
|
||||
*/
|
||||
init: function(view_manager, session, element_id, dataset, view_id, options) {
|
||||
this._super(session, element_id);
|
||||
this.view_manager = view_manager || new openerp.base.NullViewManager();
|
||||
init: function(parent, element_id, dataset, view_id, options) {
|
||||
this._super(parent, element_id);
|
||||
this.set_default_options();
|
||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
|
@ -52,13 +111,30 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
this.columns = [];
|
||||
|
||||
this.options = _.extend({}, this.defaults, options || {});
|
||||
this.flags = this.view_manager.flags || {};
|
||||
|
||||
this.set_groups(new openerp.base.ListView.Groups(this));
|
||||
|
||||
|
||||
if (this.dataset instanceof openerp.base.DataSetStatic) {
|
||||
this.groups.datagroup = new openerp.base.StaticDataGroup(this.dataset);
|
||||
}
|
||||
|
||||
this.page = 0;
|
||||
},
|
||||
/**
|
||||
* Retrieves the view's number of records per page (|| section)
|
||||
*
|
||||
* options > defaults > view_manager.action.limit > indefinite
|
||||
*
|
||||
* @returns {Number|null}
|
||||
*/
|
||||
limit: function () {
|
||||
if (this._limit === undefined) {
|
||||
this._limit = (this.options.limit
|
||||
|| this.defaults.limit
|
||||
|| (this.view_manager.action || {}).limit
|
||||
|| null);
|
||||
}
|
||||
return this._limit;
|
||||
},
|
||||
/**
|
||||
* Set a custom Group construct as the root of the List View.
|
||||
|
@ -129,27 +205,103 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
|
||||
this.setup_columns(this.fields_view.fields, grouped);
|
||||
|
||||
if (!this.fields_view.sorted) { this.fields_view.sorted = {}; }
|
||||
|
||||
this.$element.html(QWeb.render("ListView", this));
|
||||
|
||||
// Head hook
|
||||
this.$element.find('#oe-list-add')
|
||||
this.$element.find('.oe-list-add')
|
||||
.click(this.do_add_record)
|
||||
.attr('disabled', grouped && this.options.editable);
|
||||
this.$element.find('#oe-list-delete')
|
||||
this.$element.find('.oe-list-delete')
|
||||
.attr('disabled', true)
|
||||
.click(this.do_delete_selected);
|
||||
this.$element.find('thead').delegate('th[data-id]', 'click', function (e) {
|
||||
this.$element.find('thead').delegate('th.oe-sortable[data-id]', 'click', function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
self.dataset.sort($(this).data('id'));
|
||||
var $this = $(this);
|
||||
self.dataset.sort($this.data('id'));
|
||||
if ($this.find('span').length) {
|
||||
$this.find('span').toggleClass(
|
||||
'ui-icon-triangle-1-s ui-icon-triangle-1-n');
|
||||
} else {
|
||||
$this.append('<span class="ui-icon ui-icon-triangle-1-s">')
|
||||
.siblings('.oe-sortable').find('span').remove();
|
||||
}
|
||||
|
||||
// TODO: should only reload content (and set the right column to a sorted display state)
|
||||
self.reload_view();
|
||||
self.reload_content();
|
||||
});
|
||||
|
||||
this.view_manager.sidebar.set_toolbar(data.fields_view.toolbar);
|
||||
this.$element.find('.oe-list-pager')
|
||||
.delegate('button', 'click', function () {
|
||||
var $this = $(this);
|
||||
switch ($this.data('pager-action')) {
|
||||
case 'first':
|
||||
self.page = 0; break;
|
||||
case 'last':
|
||||
self.page = Math.floor(
|
||||
self.dataset.ids.length / self.limit());
|
||||
break;
|
||||
case 'next':
|
||||
self.page += 1; break;
|
||||
case 'previous':
|
||||
self.page -= 1; break;
|
||||
}
|
||||
self.reload_content();
|
||||
}).find('.oe-pager-state')
|
||||
.click(function (e) {
|
||||
e.stopPropagation();
|
||||
var $this = $(this);
|
||||
|
||||
var $select = $('<select>')
|
||||
.appendTo($this.empty())
|
||||
.click(function (e) {e.stopPropagation();})
|
||||
.append('<option value="80">80</option>' +
|
||||
'<option value="100">100</option>' +
|
||||
'<option value="200">200</option>' +
|
||||
'<option value="500">500</option>' +
|
||||
'<option value="NaN">Unlimited</option>')
|
||||
.change(function () {
|
||||
var val = parseInt($select.val(), 10);
|
||||
self._limit = (isNaN(val) ? null : val);
|
||||
self.page = 0;
|
||||
self.reload_content();
|
||||
})
|
||||
.val(self._limit || 'NaN');
|
||||
});
|
||||
if (this.options.sidebar && this.options.sidebar_id) {
|
||||
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
||||
this.sidebar.start();
|
||||
this.sidebar.add_toolbar(data.fields_view.toolbar);
|
||||
this.set_common_sidebar_sections(this.sidebar);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Configures the ListView pager based on the provided dataset's information
|
||||
*
|
||||
* Horrifying side-effect: sets the dataset's data on this.dataset?
|
||||
*
|
||||
* @param {openerp.base.DataSet} dataset
|
||||
*/
|
||||
configure_pager: function (dataset) {
|
||||
this.dataset.ids = dataset.ids;
|
||||
|
||||
var limit = this.limit(),
|
||||
total = dataset.ids.length,
|
||||
first = (this.page * limit),
|
||||
last;
|
||||
if (!limit || (total - first) < limit) {
|
||||
last = total;
|
||||
} else {
|
||||
last = first + limit;
|
||||
}
|
||||
this.$element.find('span.oe-pager-state').empty().text(_.sprintf(
|
||||
"[%d to %d] of %d", first + 1, last, total));
|
||||
|
||||
this.$element
|
||||
.find('button[data-pager-action=first], button[data-pager-action=previous]')
|
||||
.attr('disabled', this.page === 0)
|
||||
.end()
|
||||
.find('button[data-pager-action=last], button[data-pager-action=next]')
|
||||
.attr('disabled', last === total);
|
||||
},
|
||||
/**
|
||||
* Sets up the listview's columns: merges view and fields data, move
|
||||
|
@ -167,22 +319,26 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
var name = field.attrs.name;
|
||||
var column = _.extend({id: name, tag: field.tag},
|
||||
field.attrs, fields[name]);
|
||||
// attrs computer
|
||||
if (column.attrs) {
|
||||
var attrs = JSON.parse(column.attrs);
|
||||
column.attrs_for = function (fields) {
|
||||
var result = {};
|
||||
for (var attr in attrs) {
|
||||
result[attr] = domain_computer(attrs[attr], fields);
|
||||
// modifiers computer
|
||||
if (column.modifiers) {
|
||||
var modifiers = JSON.parse(column.modifiers);
|
||||
column.modifiers_for = function (fields) {
|
||||
if (!modifiers.invisible) {
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
return {
|
||||
'invisible': domain_computer(modifiers.invisible, fields)
|
||||
};
|
||||
};
|
||||
if (modifiers['tree_invisible']) {
|
||||
column.invisible = '1';
|
||||
}
|
||||
} else {
|
||||
column.attrs_for = noop;
|
||||
column.modifiers_for = noop;
|
||||
}
|
||||
return column;
|
||||
};
|
||||
|
||||
|
||||
this.columns.splice(0, this.columns.length);
|
||||
this.columns.push.apply(
|
||||
this.columns,
|
||||
|
@ -190,10 +346,10 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
if (grouped) {
|
||||
this.columns.unshift({
|
||||
id: '_group', tag: '', string: "Group", meta: true,
|
||||
attrs_for: function () { return {}; }
|
||||
modifiers_for: function () { return {}; }
|
||||
}, {
|
||||
id: '_count', tag: '', string: '#', meta: true,
|
||||
attrs_for: function () { return {}; }
|
||||
modifiers_for: function () { return {}; }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -208,16 +364,10 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
}
|
||||
var aggregation_func = column['group_operator'] || 'sum';
|
||||
|
||||
if (!column[aggregation_func]) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
field: column.id,
|
||||
type: column.type,
|
||||
return _.extend({}, column, {
|
||||
'function': aggregation_func,
|
||||
label: column[aggregation_func]
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -246,15 +396,20 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
},
|
||||
do_show: function () {
|
||||
this.$element.show();
|
||||
if (this.sidebar) {
|
||||
this.sidebar.$element.show();
|
||||
}
|
||||
if (this.hidden) {
|
||||
this.$element.find('table').append(
|
||||
this.$element.find('.oe-listview-content').append(
|
||||
this.groups.apoptosis().render());
|
||||
this.hidden = false;
|
||||
}
|
||||
this.view_manager.sidebar.do_refresh(true);
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
if (this.sidebar) {
|
||||
this.sidebar.$element.hide();
|
||||
}
|
||||
this.hidden = true;
|
||||
},
|
||||
/**
|
||||
|
@ -264,10 +419,8 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
*/
|
||||
reload_view: function (grouped) {
|
||||
var self = this;
|
||||
this.dataset.offset = 0;
|
||||
this.dataset.limit = false;
|
||||
var callback = function (field_view_get) {
|
||||
self.on_loaded(field_view_get, grouped);
|
||||
self.on_loaded(field_view_get, grouped);
|
||||
};
|
||||
if (this.embedded_view) {
|
||||
return $.Deferred().then(callback).resolve({fields_view: this.embedded_view});
|
||||
|
@ -275,8 +428,8 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
return this.rpc('/base/listview/load', {
|
||||
model: this.model,
|
||||
view_id: this.view_id,
|
||||
context: this.dataset.context,
|
||||
toolbar: !!this.flags.sidebar
|
||||
context: this.dataset.get_context(),
|
||||
toolbar: this.options.sidebar
|
||||
}, callback);
|
||||
}
|
||||
},
|
||||
|
@ -284,7 +437,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
* re-renders the content of the list view
|
||||
*/
|
||||
reload_content: function () {
|
||||
this.$element.find('table').append(
|
||||
this.$element.find('.oe-listview-content').append(
|
||||
this.groups.apoptosis().render(
|
||||
$.proxy(this, 'compute_aggregates')));
|
||||
},
|
||||
|
@ -314,9 +467,10 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
this.dataset.context = results.context;
|
||||
this.dataset.domain = results.domain;
|
||||
this.groups.datagroup = new openerp.base.DataGroup(
|
||||
this.session, this.model,
|
||||
this, this.model,
|
||||
results.domain, results.context,
|
||||
results.group_by);
|
||||
this.groups.datagroup.sort = this.dataset._sort;
|
||||
|
||||
if (_.isEmpty(results.group_by) && !results.context['group_by_no_leaf']) {
|
||||
results.group_by = null;
|
||||
|
@ -326,9 +480,9 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
$.proxy(this, 'reload_content'));
|
||||
},
|
||||
/**
|
||||
* Handles the signal to delete a line from the DOM
|
||||
* Handles the signal to delete lines from the records list
|
||||
*
|
||||
* @param {Array} ids the id of the object to delete
|
||||
* @param {Array} ids the ids of the records to delete
|
||||
*/
|
||||
do_delete: function (ids) {
|
||||
if (!ids.length) {
|
||||
|
@ -336,7 +490,8 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
}
|
||||
var self = this;
|
||||
return $.when(this.dataset.unlink(ids)).then(function () {
|
||||
self.reload_content();
|
||||
self.groups.drop_records(ids);
|
||||
self.compute_aggregates();
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -346,7 +501,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
* @param {Array} records selected record values
|
||||
*/
|
||||
do_select: function (ids, records) {
|
||||
this.$element.find('#oe-list-delete')
|
||||
this.$element.find('.oe-list-delete')
|
||||
.attr('disabled', !ids.length);
|
||||
|
||||
if (!records.length) {
|
||||
|
@ -365,16 +520,16 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
* @param {Function} callback should be called after the action is executed, if non-null
|
||||
*/
|
||||
do_action: function (name, id, callback) {
|
||||
var action = _.detect(this.columns, function (field) {
|
||||
var self = this,
|
||||
action = _.detect(this.columns, function (field) {
|
||||
return field.name === name;
|
||||
});
|
||||
if (!action) { return; }
|
||||
this.execute_action(
|
||||
action, this.dataset, this.session.action_manager,
|
||||
id, function () {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
action, this.dataset, this.session.action_manager, id, function () {
|
||||
$.when(callback.apply(this, arguments).then(function () {
|
||||
self.compute_aggregates();
|
||||
}));
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -388,7 +543,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
var self = this;
|
||||
_.extend(this.dataset, {
|
||||
domain: dataset.domain,
|
||||
context: dataset.context
|
||||
context: dataset.get_context()
|
||||
}).read_slice([], 0, false, function () {
|
||||
self.select_record(index);
|
||||
});
|
||||
|
@ -422,7 +577,6 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
compute_aggregates: function (records) {
|
||||
var columns = _(this.aggregate_columns).filter(function (column) {
|
||||
return column['function']; });
|
||||
|
||||
if (_.isEmpty(columns)) { return; }
|
||||
|
||||
if (_.isEmpty(records)) {
|
||||
|
@ -430,17 +584,39 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
}
|
||||
|
||||
var count = 0, sums = {};
|
||||
_(columns).each(function (column) { sums[column.field] = 0; });
|
||||
_(columns).each(function (column) {
|
||||
switch (column['function']) {
|
||||
case 'max':
|
||||
sums[column.id] = -Infinity;
|
||||
break;
|
||||
case 'min':
|
||||
sums[column.id] = Infinity;
|
||||
break;
|
||||
default:
|
||||
sums[column.id] = 0;
|
||||
}
|
||||
});
|
||||
_(records).each(function (record) {
|
||||
count += record.count || 1;
|
||||
_(columns).each(function (column) {
|
||||
var field = column.field;
|
||||
var field = column.id,
|
||||
value = record.values[field];
|
||||
switch (column['function']) {
|
||||
case 'sum':
|
||||
sums[field] += record.values[field];
|
||||
sums[field] += value;
|
||||
break;
|
||||
case 'avg':
|
||||
sums[field] += record.count * record.values[field];
|
||||
sums[field] += record.count * value;
|
||||
break;
|
||||
case 'min':
|
||||
if (sums[field] > value) {
|
||||
sums[field] = value;
|
||||
}
|
||||
break;
|
||||
case 'max':
|
||||
if (sums[field] < value) {
|
||||
sums[field] = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@ -448,14 +624,13 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
|
||||
var aggregates = {};
|
||||
_(columns).each(function (column) {
|
||||
var field = column.field;
|
||||
var field = column.id;
|
||||
switch (column['function']) {
|
||||
case 'sum':
|
||||
aggregates[field] = sums[field];
|
||||
break;
|
||||
case 'avg':
|
||||
aggregates[field] = sums[field] / count;
|
||||
aggregates[field] = {value: sums[field] / count};
|
||||
break;
|
||||
default:
|
||||
aggregates[field] = {value: sums[field]};
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -467,14 +642,14 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
if (!column['function']) {
|
||||
return;
|
||||
}
|
||||
var pattern = (column.type == 'integer') ? '%d' : '%.2f';
|
||||
$footer_cells.filter(_.sprintf('[data-field=%s]', column.field))
|
||||
.text(_.sprintf(pattern, aggregation[column.field]));
|
||||
|
||||
$footer_cells.filter(_.sprintf('[data-field=%s]', column.id))
|
||||
.html(openerp.base.list.render_cell(aggregation, column));
|
||||
});
|
||||
}
|
||||
// TODO: implement reorder (drag and drop rows)
|
||||
});
|
||||
openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List# */{
|
||||
openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.ListView.List# */{
|
||||
/**
|
||||
* List display for the ListView, handles basic DOM events and transforms
|
||||
* them in the relevant higher-level events, to which the list view (or
|
||||
|
@ -505,6 +680,7 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
|||
init: function (group, opts) {
|
||||
var self = this;
|
||||
this.group = group;
|
||||
this.view = group.view;
|
||||
|
||||
this.options = opts.options;
|
||||
this.columns = opts.columns;
|
||||
|
@ -533,7 +709,7 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
|||
index = self.row_position($row);
|
||||
|
||||
$(self).trigger('action', [field, record_id, function () {
|
||||
self.reload_record(index, true);
|
||||
return self.reload_record(index, true);
|
||||
}]);
|
||||
})
|
||||
.delegate('tr', 'click', function (e) {
|
||||
|
@ -553,19 +729,9 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
|||
this.$current.remove();
|
||||
}
|
||||
this.$current = this.$_element.clone(true);
|
||||
this.$current.empty().append(QWeb.render('ListView.rows', this));
|
||||
},
|
||||
get_fields_view: function () {
|
||||
// deep copy of view
|
||||
var view = $.extend(true, {}, this.group.view.fields_view);
|
||||
_(view.arch.children).each(function (widget) {
|
||||
widget.attrs.nolabel = true;
|
||||
if (widget.tag === 'button') {
|
||||
delete widget.attrs.string;
|
||||
}
|
||||
});
|
||||
view.arch.attrs.col = 2 * view.arch.children.length;
|
||||
return view;
|
||||
this.$current.empty().append(
|
||||
QWeb.render('ListView.rows', _.extend({
|
||||
render_cell: openerp.base.list.render_cell}, this)));
|
||||
},
|
||||
/**
|
||||
* Gets the ids of all currently selected records, if any
|
||||
|
@ -681,7 +847,7 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
|||
|
||||
return $.when(read_p).then(function () {
|
||||
self.$current.children().eq(record_index)
|
||||
.replaceWith(self.render_record(record_index)); })
|
||||
.replaceWith(self.render_record(record_index)); });
|
||||
},
|
||||
/**
|
||||
* Renders a list record to HTML
|
||||
|
@ -695,12 +861,31 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
|||
options: this.options,
|
||||
row: this.rows[record_index],
|
||||
row_parity: (record_index % 2 === 0) ? 'even' : 'odd',
|
||||
row_index: record_index
|
||||
row_index: record_index,
|
||||
render_cell: openerp.base.list.render_cell
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Stops displaying the records matching the provided ids.
|
||||
*
|
||||
* @param {Array} ids identifiers of the records to remove
|
||||
*/
|
||||
drop_records: function (ids) {
|
||||
var self = this;
|
||||
_(this.rows).chain()
|
||||
.map(function (record, index) {
|
||||
return {index: index, id: record.data.id.value};
|
||||
}).filter(function (record) {
|
||||
return _(ids).contains(record.id);
|
||||
}).reverse()
|
||||
.each(function (record) {
|
||||
self.$current.find('tr:eq(' + record.index + ')').remove();
|
||||
self.rows.splice(record.index, 1);
|
||||
})
|
||||
}
|
||||
// drag and drop
|
||||
});
|
||||
openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Groups# */{
|
||||
openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.base.ListView.Groups# */{
|
||||
passtrough_events: 'action deleted row_link',
|
||||
/**
|
||||
* Grouped display for the ListView. Handles basic DOM events and interacts
|
||||
|
@ -715,13 +900,10 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
this.columns = view.columns;
|
||||
this.datagroup = null;
|
||||
|
||||
this.sections = [];
|
||||
this.$row = null;
|
||||
this.children = {};
|
||||
},
|
||||
pad: function ($row) {
|
||||
if (this.options.selectable) {
|
||||
$row.append('<td>');
|
||||
}
|
||||
|
||||
this.page = 0;
|
||||
},
|
||||
make_fragment: function () {
|
||||
return document.createDocumentFragment();
|
||||
|
@ -753,10 +935,35 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
}
|
||||
return red_letter_tboday;
|
||||
},
|
||||
make_paginator: function () {
|
||||
var self = this;
|
||||
var $prev = $('<button type="button" data-pager-action="previous"><</button>')
|
||||
.click(function (e) {
|
||||
e.stopPropagation();
|
||||
self.page -= 1;
|
||||
|
||||
self.$row.closest('tbody').next()
|
||||
.replaceWith(self.render());
|
||||
});
|
||||
var $next = $('<button type="button" data-pager-action="next">></button>')
|
||||
.click(function (e) {
|
||||
e.stopPropagation();
|
||||
self.page += 1;
|
||||
|
||||
self.$row.closest('tbody').next()
|
||||
.replaceWith(self.render());
|
||||
});
|
||||
this.$row.children().last()
|
||||
.append($prev)
|
||||
.append('<span class="oe-pager-state"></span>')
|
||||
.append($next);
|
||||
},
|
||||
open: function (point_insertion) {
|
||||
this.render().insertAfter(point_insertion);
|
||||
this.make_paginator();
|
||||
},
|
||||
close: function () {
|
||||
this.$row.children().last().empty();
|
||||
this.apoptosis();
|
||||
},
|
||||
/**
|
||||
|
@ -788,7 +995,7 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
self.bind_child_events(child);
|
||||
child.datagroup = group;
|
||||
|
||||
var $row = $('<tr>');
|
||||
var $row = child.$row = $('<tr>');
|
||||
if (group.openable) {
|
||||
$row.click(function (e) {
|
||||
if (!$row.data('open')) {
|
||||
|
@ -808,11 +1015,16 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
}
|
||||
placeholder.appendChild($row[0]);
|
||||
|
||||
var $group_column = $('<th>').appendTo($row);
|
||||
var $group_column = $('<th class="oe-group-name">').appendTo($row);
|
||||
// Don't fill this if group_by_no_leaf but no group_by
|
||||
if (group.grouped_on) {
|
||||
// Don't fill this if group_by_no_leaf but no group_by
|
||||
$group_column
|
||||
.text((group.value instanceof Array ? group.value[1] : group.value));
|
||||
var row_data = {};
|
||||
row_data[group.grouped_on] = group;
|
||||
var group_column = _(self.columns).detect(function (column) {
|
||||
return column.id === group.grouped_on; });
|
||||
$group_column.html(openerp.base.list.render_cell(
|
||||
row_data, group_column, "Undefined"
|
||||
));
|
||||
if (group.openable) {
|
||||
// Make openable if not terminal group & group_by_no_leaf
|
||||
$group_column
|
||||
|
@ -822,8 +1034,10 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
self.indent($group_column, group.level);
|
||||
// count column
|
||||
$('<td>').text(group.length).appendTo($row);
|
||||
|
||||
self.pad($row);
|
||||
|
||||
if (self.options.selectable) {
|
||||
$row.append('<td>');
|
||||
}
|
||||
_(self.columns).chain()
|
||||
.filter(function (column) {return !column.invisible;})
|
||||
.each(function (column) {
|
||||
|
@ -844,6 +1058,9 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
$row.append('<td>');
|
||||
}
|
||||
});
|
||||
if (self.options.deletable) {
|
||||
$row.append('<td class="oe-group-pagination">');
|
||||
}
|
||||
});
|
||||
return placeholder;
|
||||
},
|
||||
|
@ -867,6 +1084,7 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
},
|
||||
render_dataset: function (dataset) {
|
||||
var rows = [],
|
||||
self = this,
|
||||
list = new openerp.base.ListView.List(this, {
|
||||
options: this.options,
|
||||
columns: this.columns,
|
||||
|
@ -875,11 +1093,30 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
});
|
||||
this.bind_child_events(list);
|
||||
|
||||
var d = new $.Deferred();
|
||||
var view = this.view,
|
||||
limit = view.limit(),
|
||||
d = new $.Deferred(),
|
||||
page = this.datagroup.openable ? this.page : view.page;
|
||||
|
||||
dataset.read_slice(
|
||||
_.filter(_.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name'), _.identity),
|
||||
0, false,
|
||||
page * limit, limit,
|
||||
function (records) {
|
||||
if (!self.datagroup.openable) {
|
||||
view.configure_pager(dataset);
|
||||
} else {
|
||||
var pages = Math.ceil(dataset.ids.length / limit);
|
||||
self.$row
|
||||
.find('.oe-pager-state')
|
||||
.text(_.sprintf('%d/%d', page + 1, pages))
|
||||
.end()
|
||||
.find('button[data-pager-action=previous]')
|
||||
.attr('disabled', page === 0)
|
||||
.end()
|
||||
.find('button[data-pager-action=next]')
|
||||
.attr('disabled', page === pages - 1);
|
||||
}
|
||||
|
||||
var form_records = _(records).map(
|
||||
$.proxy(list, 'transform_record'));
|
||||
|
||||
|
@ -890,22 +1127,67 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
});
|
||||
return d.promise();
|
||||
},
|
||||
setup_resequence_rows: function (list, dataset) {
|
||||
// drag and drop enabled if list is not sorted and there is a
|
||||
// "sequence" column in the view.
|
||||
if ((dataset.sort && dataset.sort())
|
||||
|| !_(this.columns).any(function (column) {
|
||||
return column.name === 'sequence'; })) {
|
||||
return;
|
||||
}
|
||||
// ondrop, move relevant record & fix sequences
|
||||
list.$current.sortable({
|
||||
stop: function (event, ui) {
|
||||
var from = ui.item.data('index'),
|
||||
to = ui.item.prev().data('index') || 0;
|
||||
if (from === to) { return; }
|
||||
list.rows.splice(to, 0, list.rows.splice(from, 1)[0]);
|
||||
|
||||
ui.item.parent().children().each(function (i, e) {
|
||||
// reset record-index accelerators on rows and even/odd
|
||||
var even = i%2 === 0;
|
||||
$(e).data('index', i)
|
||||
.toggleClass('even', even)
|
||||
.toggleClass('odd', !even);
|
||||
});
|
||||
|
||||
// resequencing time!
|
||||
var data, index = to,
|
||||
// if drag to 1st row (to = 0), start sequencing from 0
|
||||
// (exclusive lower bound)
|
||||
seq = to ? list.rows[to - 1].data.sequence.value : 0;
|
||||
while (++seq, data = list.rows[index++].data) {
|
||||
data.sequence.value = seq;
|
||||
// write are independent from one another, so we can just
|
||||
// launch them all at the same time and we don't really
|
||||
// give a fig about when they're done
|
||||
dataset.write(data.id.value, {sequence: seq});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
render: function (post_render) {
|
||||
var self = this;
|
||||
var $element = $('<tbody>');
|
||||
this.elements = [$element[0]];
|
||||
this.datagroup.list(function (groups) {
|
||||
$element[0].appendChild(
|
||||
self.render_groups(groups));
|
||||
if (post_render) { post_render(); }
|
||||
}, function (dataset) {
|
||||
self.render_dataset(dataset).then(function (list) {
|
||||
self.children[null] = list;
|
||||
self.elements =
|
||||
[list.$current.replaceAll($element)[0]];
|
||||
|
||||
this.datagroup.list(
|
||||
_(this.view.visible_columns).chain()
|
||||
.filter(function (column) { return column.tag === 'field' })
|
||||
.pluck('name').value(),
|
||||
function (groups) {
|
||||
$element[0].appendChild(
|
||||
self.render_groups(groups));
|
||||
if (post_render) { post_render(); }
|
||||
}, function (dataset) {
|
||||
self.render_dataset(dataset).then(function (list) {
|
||||
self.children[null] = list;
|
||||
self.elements =
|
||||
[list.$current.replaceAll($element)[0]];
|
||||
self.setup_resequence_rows(list, dataset);
|
||||
if (post_render) { post_render(); }
|
||||
});
|
||||
});
|
||||
});
|
||||
return $element;
|
||||
},
|
||||
/**
|
||||
|
@ -943,6 +1225,19 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
|||
.map(function (child) {
|
||||
return child.get_records();
|
||||
}).flatten().value();
|
||||
},
|
||||
/**
|
||||
* Stops displaying the records with the linked ids, assumes these records
|
||||
* were deleted from the DB.
|
||||
*
|
||||
* This is the up-signal from the `deleted` event on groups and lists.
|
||||
*
|
||||
* @param {Array} ids list of identifier of the records to remove.
|
||||
*/
|
||||
drop_records: function (ids) {
|
||||
_.each(this.children, function (child) {
|
||||
child.drop_records(ids);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
openerp.base.search = function(openerp) {
|
||||
|
||||
openerp.base.SearchView = openerp.base.Controller.extend({
|
||||
init: function(view_manager, session, element_id, dataset, view_id, defaults) {
|
||||
this._super(session, element_id);
|
||||
this.view_manager = view_manager || new openerp.base.NullViewManager();
|
||||
openerp.base.SearchView = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id, dataset, view_id, defaults) {
|
||||
this._super(parent, element_id);
|
||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
|
@ -14,10 +14,13 @@ openerp.base.SearchView = openerp.base.Controller.extend({
|
|||
this.enabled_filters = [];
|
||||
|
||||
this.has_focus = false;
|
||||
|
||||
this.ready = $.Deferred();
|
||||
},
|
||||
start: function() {
|
||||
//this.log('Starting SearchView '+this.model+this.view_id)
|
||||
return this.rpc("/base/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
|
||||
this.rpc("/base/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
|
||||
return this.ready.promise();
|
||||
},
|
||||
show: function () {
|
||||
this.$element.show();
|
||||
|
@ -107,12 +110,13 @@ openerp.base.SearchView = openerp.base.Controller.extend({
|
|||
}
|
||||
},
|
||||
on_loaded: function(data) {
|
||||
var lines = this.make_widgets(
|
||||
data.fields_view['arch'].children,
|
||||
data.fields_view.fields);
|
||||
var self = this,
|
||||
lines = this.make_widgets(
|
||||
data.fields_view['arch'].children,
|
||||
data.fields_view.fields);
|
||||
|
||||
// for extended search view
|
||||
var ext = new openerp.base.search.ExtendedSearch(null, this.session, this.model);
|
||||
var ext = new openerp.base.search.ExtendedSearch(this, this.model);
|
||||
lines.push([ext]);
|
||||
this.inputs.push(ext);
|
||||
|
||||
|
@ -121,6 +125,7 @@ openerp.base.SearchView = openerp.base.Controller.extend({
|
|||
'lines': lines,
|
||||
'defaults': this.defaults
|
||||
});
|
||||
|
||||
// We don't understand why the following commented line does not work in Chrome but
|
||||
// the non-commented line does. As far as we investigated, only God knows.
|
||||
//this.$element.html(render);
|
||||
|
@ -132,30 +137,90 @@ openerp.base.SearchView = openerp.base.Controller.extend({
|
|||
.submit(this.do_search)
|
||||
.bind('reset', this.do_clear);
|
||||
// start() all the widgets
|
||||
_(lines).chain().flatten().each(function (widget) {
|
||||
widget.start();
|
||||
var widget_starts = _(lines).chain().flatten().map(function (widget) {
|
||||
return widget.start();
|
||||
}).value();
|
||||
|
||||
$.when.apply(null, widget_starts).then(function () {
|
||||
self.ready.resolve();
|
||||
});
|
||||
|
||||
// filters management
|
||||
this.$element.find(".oe_search-view-filters-management").change(this.on_filters_management);
|
||||
this.reload_managed_filters();
|
||||
},
|
||||
reload_managed_filters: function() {
|
||||
var self = this;
|
||||
return this.rpc('/base/searchview/get_filters', {
|
||||
model: this.dataset.model
|
||||
}).then(function(result) {
|
||||
self.managed_filters = result;
|
||||
var filters = self.$element.find(".oe_search-view-filters-management");
|
||||
filters.html(QWeb.render("SearchView.managed-filters", {filters: result}));
|
||||
filters.change(self.on_filters_management);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Handle event when the user make a selection in the filters management select box.
|
||||
*/
|
||||
on_filters_management: function(e) {
|
||||
var self = this;
|
||||
var select = this.$element.find(".oe_search-view-filters-management");
|
||||
var val = select.val();
|
||||
select.val("_filters");
|
||||
|
||||
if (val.slice(0,1) == "_") // useless action
|
||||
if (val.slice(0,1) == "_") { // useless action
|
||||
select.val("_filters");
|
||||
return;
|
||||
}
|
||||
if (val.slice(0, "get:".length) == "get:") {
|
||||
val = val.slice("get:".length);
|
||||
//TODO niv
|
||||
val = parseInt(val);
|
||||
var filter = this.managed_filters[val];
|
||||
this.on_search([filter.domain], [filter.context], []);
|
||||
} else if (val == "save_filter") {
|
||||
//TODO niv
|
||||
select.val("_filters");
|
||||
var data = this.build_search_data();
|
||||
var context = new openerp.base.CompoundContext();
|
||||
_.each(data.contexts, function(x) {
|
||||
context.add(x);
|
||||
});
|
||||
var domain = new openerp.base.CompoundDomain();
|
||||
_.each(data.domains, function(x) {
|
||||
domain.add(x);
|
||||
});
|
||||
var dial_html = QWeb.render("SearchView.managed-filters.add");
|
||||
var $dial = $(dial_html);
|
||||
$dial.dialog({
|
||||
modal: true,
|
||||
title: "Filter Entry",
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
$(this).dialog("close");
|
||||
},
|
||||
OK: function() {
|
||||
$(this).dialog("close");
|
||||
var name = $(this).find("input").val();
|
||||
self.rpc('/base/searchview/save_filter', {
|
||||
model: self.dataset.model,
|
||||
context_to_save: context,
|
||||
domain: domain,
|
||||
name: name
|
||||
}).then(function(result) {
|
||||
self.reload_managed_filters();
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
} else { // manage_filters
|
||||
//TODO niv
|
||||
select.val("_filters");
|
||||
this.do_action({
|
||||
res_model: 'ir.filters',
|
||||
views: [[false, 'list'], [false, 'form']],
|
||||
type: 'ir.actions.act_window',
|
||||
context: {"search_default_user_id": this.session.uid,
|
||||
"search_default_model_id": this.dataset.model},
|
||||
target: "current",
|
||||
limit : 80,
|
||||
auto_search : true
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
@ -170,11 +235,25 @@ openerp.base.SearchView = openerp.base.Controller.extend({
|
|||
* @param e jQuery event object coming from the "Search" button
|
||||
*/
|
||||
do_search: function (e) {
|
||||
// reset filters management
|
||||
var select = this.$element.find(".oe_search-view-filters-management");
|
||||
select.val("_filters");
|
||||
|
||||
if (e && e.preventDefault) { e.preventDefault(); }
|
||||
|
||||
var domains = [], contexts = [];
|
||||
var data = this.build_search_data();
|
||||
|
||||
var errors = [];
|
||||
if (data.errors.length) {
|
||||
this.on_invalid(data.errors);
|
||||
return;
|
||||
}
|
||||
|
||||
this.on_search(data.domains, data.contexts, data.groupbys);
|
||||
},
|
||||
build_search_data: function() {
|
||||
var domains = [],
|
||||
contexts = [],
|
||||
errors = [];
|
||||
|
||||
_.each(this.inputs, function (input) {
|
||||
try {
|
||||
|
@ -196,19 +275,13 @@ openerp.base.SearchView = openerp.base.Controller.extend({
|
|||
}
|
||||
});
|
||||
|
||||
if (errors.length) {
|
||||
this.on_invalid(errors);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: do we need to handle *fields* with group_by in their context?
|
||||
var groupbys = _(this.enabled_filters)
|
||||
.chain()
|
||||
.map(function (filter) { return filter.get_context();})
|
||||
.compact()
|
||||
.value();
|
||||
|
||||
this.on_search(domains, contexts, groupbys);
|
||||
return {domains: domains, contexts: contexts, errors: errors, groupbys: groupbys};
|
||||
},
|
||||
/**
|
||||
* Triggered after the SearchView has collected all relevant domains and
|
||||
|
@ -293,8 +366,7 @@ openerp.base.search.fields = new openerp.base.Registry({
|
|||
'many2one': 'openerp.base.search.ManyToOneField',
|
||||
'many2many': 'openerp.base.search.ManyToManyField'
|
||||
});
|
||||
openerp.base.search.Invalid = Class.extend(
|
||||
/** @lends openerp.base.search.Invalid# */{
|
||||
openerp.base.search.Invalid = openerp.base.Class.extend( /** @lends openerp.base.search.Invalid# */{
|
||||
/**
|
||||
* Exception thrown by search widgets when they hold invalid values,
|
||||
* which they can not return when asked.
|
||||
|
@ -314,14 +386,13 @@ openerp.base.search.Invalid = Class.extend(
|
|||
': [' + this.value + '] is ' + this.message);
|
||||
}
|
||||
});
|
||||
openerp.base.search.Widget = openerp.base.Controller.extend(
|
||||
/** @lends openerp.base.search.Widget# */{
|
||||
openerp.base.search.Widget = openerp.base.Widget.extend( /** @lends openerp.base.search.Widget# */{
|
||||
template: null,
|
||||
/**
|
||||
* Root class of all search widgets
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.Controller
|
||||
* @extends openerp.base.Widget
|
||||
*
|
||||
* @param view the ancestor view of this widget
|
||||
*/
|
||||
|
@ -395,8 +466,6 @@ openerp.base.search.add_expand_listener = function($root) {
|
|||
};
|
||||
openerp.base.search.Group = openerp.base.search.Widget.extend({
|
||||
template: 'SearchView.group',
|
||||
// TODO: contain stuff
|
||||
// TODO: @expand
|
||||
init: function (view_section, view, fields) {
|
||||
this._super(view);
|
||||
this.attrs = view_section.attrs;
|
||||
|
@ -414,8 +483,7 @@ openerp.base.search.Group = openerp.base.search.Widget.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.search.Input = openerp.base.search.Widget.extend(
|
||||
/** @lends openerp.base.search.Input# */{
|
||||
openerp.base.search.Input = openerp.base.search.Widget.extend( /** @lends openerp.base.search.Input# */{
|
||||
/**
|
||||
* @constructs
|
||||
* @extends openerp.base.search.Widget
|
||||
|
@ -437,7 +505,6 @@ openerp.base.search.Input = openerp.base.search.Widget.extend(
|
|||
});
|
||||
openerp.base.search.Filter = openerp.base.search.Input.extend({
|
||||
template: 'SearchView.filter',
|
||||
// TODO: force rendering
|
||||
init: function (node, view) {
|
||||
this._super(view);
|
||||
this.attrs = node.attrs;
|
||||
|
@ -486,13 +553,9 @@ openerp.base.search.Filter = openerp.base.search.Input.extend({
|
|||
return this.attrs.domain;
|
||||
}
|
||||
});
|
||||
openerp.base.search.Field = openerp.base.search.Input.extend(
|
||||
/** @lends openerp.base.search.Field# */ {
|
||||
openerp.base.search.Field = openerp.base.search.Input.extend( /** @lends openerp.base.search.Field# */ {
|
||||
template: 'SearchView.field',
|
||||
default_operator: '=',
|
||||
// TODO: set default values
|
||||
// TODO: get context, domain
|
||||
// TODO: holds Filters
|
||||
/**
|
||||
* @constructs
|
||||
* @extends openerp.base.search.Input
|
||||
|
@ -530,9 +593,7 @@ openerp.base.search.Field = openerp.base.search.Input.extend(
|
|||
},
|
||||
get_domain: function () {
|
||||
var val = this.get_value();
|
||||
|
||||
var has_value = (val !== null && val !== '');
|
||||
if(!has_value) {
|
||||
if (val === null || val === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -544,9 +605,7 @@ openerp.base.search.Field = openerp.base.search.Input.extend(
|
|||
this.get_value()
|
||||
]];
|
||||
}
|
||||
return _.extend(
|
||||
{}, domain,
|
||||
{own_values: {self: val}});
|
||||
return _.extend({}, domain, {own_values: {self: val}});
|
||||
}
|
||||
});
|
||||
/**
|
||||
|
@ -559,8 +618,7 @@ openerp.base.search.Field = openerp.base.search.Input.extend(
|
|||
* @class
|
||||
* @extends openerp.base.search.Field
|
||||
*/
|
||||
openerp.base.search.CharField = openerp.base.search.Field.extend(
|
||||
/** @lends openerp.base.search.CharField# */ {
|
||||
openerp.base.search.CharField = openerp.base.search.Field.extend( /** @lends openerp.base.search.CharField# */ {
|
||||
default_operator: 'ilike',
|
||||
get_value: function () {
|
||||
return this.$element.val();
|
||||
|
@ -599,32 +657,40 @@ openerp.base.search.BooleanField = openerp.base.search.Field.extend({
|
|||
}
|
||||
}
|
||||
});
|
||||
openerp.base.search.IntegerField = openerp.base.search.Field.extend({
|
||||
openerp.base.search.NumberField = openerp.base.search.Field.extend(/** @lends openerp.base.search.NumberField# */{
|
||||
get_value: function () {
|
||||
if (!this.$element.val()) {
|
||||
return null;
|
||||
}
|
||||
var val = parseInt(this.$element.val());
|
||||
var check = Number(this.$element.val());
|
||||
if (isNaN(check) || val !== check) {
|
||||
var val = this.parse(this.$element.val()),
|
||||
check = Number(this.$element.val());
|
||||
if (isNaN(val) || val !== check) {
|
||||
this.$element.addClass('error');
|
||||
throw new openerp.base.search.Invalid(
|
||||
this.attrs.name, this.$element.val(), "not a valid integer");
|
||||
this.attrs.name, this.$element.val(), this.error_message);
|
||||
}
|
||||
this.$element.removeClass('error');
|
||||
return val;
|
||||
}
|
||||
});
|
||||
openerp.base.search.FloatField = openerp.base.search.Field.extend({
|
||||
get_value: function () {
|
||||
var val = Number(this.$element.val());
|
||||
if (isNaN(val)) {
|
||||
this.$element.addClass('error');
|
||||
throw new openerp.base.search.Invalid(
|
||||
this.attrs.name, this.$element.val(), "not a valid number");
|
||||
}
|
||||
this.$element.removeClass('error');
|
||||
return val;
|
||||
/**
|
||||
* @class
|
||||
* @extends openerp.base.search.NumberField
|
||||
*/
|
||||
openerp.base.search.IntegerField = openerp.base.search.NumberField.extend(/** @lends openerp.base.search.IntegerField# */{
|
||||
error_message: "not a valid integer",
|
||||
parse: function (value) {
|
||||
return parseInt(value, 10);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* @class
|
||||
* @extends openerp.base.search.NumberField
|
||||
*/
|
||||
openerp.base.search.FloatField = openerp.base.search.NumberField.extend(/** @lends openerp.base.search.FloatField# */{
|
||||
error_message: "not a valid number",
|
||||
parse: function (value) {
|
||||
return parseFloat(value);
|
||||
}
|
||||
});
|
||||
openerp.base.search.SelectionField = openerp.base.search.Field.extend({
|
||||
|
@ -633,12 +699,7 @@ openerp.base.search.SelectionField = openerp.base.search.Field.extend({
|
|||
return this.$element.val();
|
||||
}
|
||||
});
|
||||
/**
|
||||
* @class
|
||||
* @extends openerp.base.search.Field
|
||||
*/
|
||||
openerp.base.search.DateField = openerp.base.search.Field.extend(
|
||||
/** @lends openerp.base.search.DateField# */{
|
||||
openerp.base.search.DateField = openerp.base.search.Field.extend( /** @lends openerp.base.search.DateField# */{
|
||||
template: 'SearchView.fields.date',
|
||||
/**
|
||||
* enables date picker on the HTML widgets
|
||||
|
@ -663,8 +724,12 @@ openerp.base.search.DateField = openerp.base.search.Field.extend(
|
|||
get_values: function () {
|
||||
var values_array = this.$element.find('input').serializeArray();
|
||||
|
||||
var from = values_array[0].value;
|
||||
var to = values_array[1].value;
|
||||
if (!values_array || !values_array[0]) {
|
||||
throw new openerp.base.search.Invalid(
|
||||
this.attrs.name, null, "widget not ready");
|
||||
}
|
||||
var from = values_array[0].value,
|
||||
to = values_array[1].value;
|
||||
|
||||
var field_values = {};
|
||||
if (from) {
|
||||
|
@ -709,33 +774,100 @@ openerp.base.search.DateField = openerp.base.search.Field.extend(
|
|||
openerp.base.search.DateTimeField = openerp.base.search.DateField.extend({
|
||||
// TODO: time?
|
||||
});
|
||||
openerp.base.search.OneToManyField = openerp.base.search.IntegerField.extend({
|
||||
openerp.base.search.OneToManyField = openerp.base.search.CharField.extend({
|
||||
// TODO: .relation, .context, .domain
|
||||
});
|
||||
openerp.base.search.ManyToOneField = openerp.base.search.IntegerField.extend({
|
||||
openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({
|
||||
// TODO: @widget
|
||||
// TODO: .relation, .selection, .context, .domain
|
||||
init: function (view_section, field, view) {
|
||||
this._super(view_section, field, view);
|
||||
var self = this;
|
||||
this.got_name = $.Deferred().then(function () {
|
||||
self.$element.val(self.name);
|
||||
});
|
||||
this.dataset = new openerp.base.DataSet(
|
||||
this.view, this.attrs['relation']);
|
||||
},
|
||||
start: function () {
|
||||
this._super();
|
||||
this.setup_autocomplete();
|
||||
var started = $.Deferred();
|
||||
this.got_name.then(function () { started.resolve();},
|
||||
function () { started.resolve(); });
|
||||
return started.promise();
|
||||
},
|
||||
setup_autocomplete: function () {
|
||||
var self = this;
|
||||
this.$element.autocomplete({
|
||||
source: function (req, resp) {
|
||||
self.dataset.name_search(
|
||||
req.term, self.attrs.domain, 'ilike', 8, function (data) {
|
||||
resp(_.map(data, function (result) {
|
||||
return {id: result[0], label: result[1]}
|
||||
}));
|
||||
});
|
||||
},
|
||||
select: function (event, ui) {
|
||||
self.id = ui.item.id;
|
||||
self.name = ui.item.label;
|
||||
},
|
||||
delay: 0
|
||||
})
|
||||
},
|
||||
on_name_get: function (name_get) {
|
||||
if (!name_get.length) {
|
||||
delete this.id;
|
||||
this.got_name.reject();
|
||||
return;
|
||||
}
|
||||
this.name = name_get[0][1];
|
||||
this.got_name.resolve();
|
||||
},
|
||||
render: function (defaults) {
|
||||
if (defaults[this.attrs.name]) {
|
||||
this.id = defaults[this.attrs.name];
|
||||
// TODO: maybe this should not be completely removed
|
||||
delete defaults[this.attrs.name];
|
||||
this.dataset.name_get([this.id], $.proxy(this, 'on_name_get'));
|
||||
} else {
|
||||
this.got_name.reject();
|
||||
}
|
||||
return this._super(defaults);
|
||||
},
|
||||
get_domain: function () {
|
||||
if (this.id && this.name) {
|
||||
if (this.$element.val() === this.name) {
|
||||
return [[this.attrs.name, '=', this.id]];
|
||||
} else {
|
||||
delete this.id;
|
||||
delete this.name;
|
||||
}
|
||||
}
|
||||
return this._super();
|
||||
}
|
||||
});
|
||||
openerp.base.search.ManyToManyField = openerp.base.search.IntegerField.extend({
|
||||
openerp.base.search.ManyToManyField = openerp.base.search.CharField.extend({
|
||||
// TODO: .related_columns (Array), .context, .domain
|
||||
});
|
||||
|
||||
openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearch = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search',
|
||||
identifier_prefix: 'extended-search',
|
||||
init: function (parent, session, model) {
|
||||
this._super(parent, session);
|
||||
init: function (parent, model) {
|
||||
this._super(parent);
|
||||
this.model = model;
|
||||
},
|
||||
add_group: function() {
|
||||
var group = new openerp.base.search.ExtendedSearchGroup(this, this.fields);
|
||||
var render = group.render();
|
||||
this.$element.find('.searchview_extended_groups_list').append(render);
|
||||
group.start();
|
||||
group.appendTo(this.$element.find('.searchview_extended_groups_list'));
|
||||
this.check_last_element();
|
||||
},
|
||||
start: function () {
|
||||
this._super();
|
||||
if (!this.$element) {
|
||||
return; // not a logical state but sometimes it happens
|
||||
}
|
||||
this.$element.closest("table.oe-searchview-render-line").css("display", "none");
|
||||
var self = this;
|
||||
this.rpc("/base/searchview/fields_get",
|
||||
|
@ -751,10 +883,13 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
|
|||
return null;
|
||||
},
|
||||
get_domain: function() {
|
||||
if (!this.$element) {
|
||||
return null; // not a logical state but sometimes it happens
|
||||
}
|
||||
if(this.$element.closest("table.oe-searchview-render-line").css("display") == "none") {
|
||||
return null;
|
||||
}
|
||||
return _.reduce(this.children,
|
||||
return _.reduce(this.widget_children,
|
||||
function(mem, x) { return mem.concat(x.get_domain());}, []);
|
||||
},
|
||||
on_activate: function() {
|
||||
|
@ -773,12 +908,14 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
|
|||
}
|
||||
},
|
||||
check_last_element: function() {
|
||||
_.each(this.children, function(x) {x.set_last_group(false);});
|
||||
this.children[this.children.length - 1].set_last_group(true);
|
||||
_.each(this.widget_children, function(x) {x.set_last_group(false);});
|
||||
if (this.widget_children.length >= 1) {
|
||||
this.widget_children[this.widget_children.length - 1].set_last_group(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchGroup = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.group',
|
||||
identifier_prefix: 'extended-search-group',
|
||||
init: function (parent, fields) {
|
||||
|
@ -787,7 +924,7 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
|||
},
|
||||
add_prop: function() {
|
||||
var prop = new openerp.base.search.ExtendedSearchProposition(this, this.fields);
|
||||
var render = prop.render({'index': this.children.length - 1});
|
||||
var render = prop.render({'index': this.widget_children.length - 1});
|
||||
this.$element.find('.searchview_extended_propositions_list').append(render);
|
||||
prop.start();
|
||||
},
|
||||
|
@ -804,7 +941,7 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
|||
});
|
||||
},
|
||||
get_domain: function() {
|
||||
var props = _(this.children).chain().map(function(x) {
|
||||
var props = _(this.widget_children).chain().map(function(x) {
|
||||
return x.get_proposition();
|
||||
}).compact().value();
|
||||
var choice = this.$element.find(".searchview_extended_group_choice").val();
|
||||
|
@ -814,9 +951,9 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
|||
props);
|
||||
},
|
||||
stop: function() {
|
||||
var parent = this.parent;
|
||||
if (this.parent.children.length == 1)
|
||||
this.parent.hide();
|
||||
var parent = this.widget_parent;
|
||||
if (this.widget_parent.widget_children.length == 1)
|
||||
this.widget_parent.hide();
|
||||
this._super();
|
||||
parent.check_last_element();
|
||||
},
|
||||
|
@ -828,7 +965,7 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition',
|
||||
identifier_prefix: 'extended-search-proposition',
|
||||
init: function (parent, fields) {
|
||||
|
@ -853,9 +990,12 @@ openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
|
|||
});
|
||||
},
|
||||
stop: function() {
|
||||
if (this.parent.children.length == 1)
|
||||
this.parent.stop();
|
||||
var parent;
|
||||
if (this.widget_parent.widget_children.length == 1)
|
||||
parent = this.widget_parent;
|
||||
this._super();
|
||||
if (parent)
|
||||
parent.stop();
|
||||
},
|
||||
changed: function() {
|
||||
var nval = this.$element.find(".searchview_extended_prop_field").val();
|
||||
|
@ -887,7 +1027,7 @@ openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
|
|||
if (! e instanceof openerp.base.KeyNotFound) {
|
||||
throw e;
|
||||
}
|
||||
var type = "char";
|
||||
type = "char";
|
||||
this.log('Unknow field type ' + e.key);
|
||||
}
|
||||
this.value = new (openerp.base.search.custom_filters.get_object(type))
|
||||
|
@ -915,7 +1055,7 @@ openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.search.ExtendedSearchProposition.Char = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition.Char = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition.char',
|
||||
identifier_prefix: 'extended-search-proposition-char',
|
||||
operators: [
|
||||
|
@ -932,7 +1072,7 @@ openerp.base.search.ExtendedSearchProposition.Char = openerp.base.BaseWidget.ext
|
|||
return this.$element.val();
|
||||
}
|
||||
});
|
||||
openerp.base.search.ExtendedSearchProposition.DateTime = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition.DateTime = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition.datetime',
|
||||
identifier_prefix: 'extended-search-proposition-datetime',
|
||||
operators: [
|
||||
|
@ -954,7 +1094,7 @@ openerp.base.search.ExtendedSearchProposition.DateTime = openerp.base.BaseWidget
|
|||
});
|
||||
}
|
||||
});
|
||||
openerp.base.search.ExtendedSearchProposition.Date = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition.Date = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition.date',
|
||||
identifier_prefix: 'extended-search-proposition-date',
|
||||
operators: [
|
||||
|
@ -976,7 +1116,7 @@ openerp.base.search.ExtendedSearchProposition.Date = openerp.base.BaseWidget.ext
|
|||
});
|
||||
}
|
||||
});
|
||||
openerp.base.search.ExtendedSearchProposition.Integer = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition.Integer = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition.integer',
|
||||
identifier_prefix: 'extended-search-proposition-integer',
|
||||
operators: [
|
||||
|
@ -988,15 +1128,14 @@ openerp.base.search.ExtendedSearchProposition.Integer = openerp.base.BaseWidget.
|
|||
{value: "<=", text: "less or equal than"}
|
||||
],
|
||||
get_value: function() {
|
||||
val = this.$element.val();
|
||||
val2 = parseFloat(val);
|
||||
if(val2 != 0 && !val2) {
|
||||
var value = parseFloat(this.$element.val());
|
||||
if(value != 0 && !value) {
|
||||
return "";
|
||||
}
|
||||
return Math.round(val2);
|
||||
return Math.round(value);
|
||||
}
|
||||
});
|
||||
openerp.base.search.ExtendedSearchProposition.Float = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition.Float = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition.float',
|
||||
identifier_prefix: 'extended-search-proposition-float',
|
||||
operators: [
|
||||
|
@ -1008,15 +1147,14 @@ openerp.base.search.ExtendedSearchProposition.Float = openerp.base.BaseWidget.ex
|
|||
{value: "<=", text: "less or equal than"}
|
||||
],
|
||||
get_value: function() {
|
||||
val = this.$element.val();
|
||||
val2 = parseFloat(val);
|
||||
if(val2 != 0 && !val2) {
|
||||
var value = parseFloat(this.$element.val());
|
||||
if(value != 0 && !value) {
|
||||
return "";
|
||||
}
|
||||
return val2;
|
||||
return value;
|
||||
}
|
||||
});
|
||||
openerp.base.search.ExtendedSearchProposition.Selection = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition.Selection = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition.selection',
|
||||
identifier_prefix: 'extended-search-proposition-selection',
|
||||
operators: [
|
||||
|
@ -1030,7 +1168,7 @@ openerp.base.search.ExtendedSearchProposition.Selection = openerp.base.BaseWidge
|
|||
return this.$element.val();
|
||||
}
|
||||
});
|
||||
openerp.base.search.ExtendedSearchProposition.Boolean = openerp.base.BaseWidget.extend({
|
||||
openerp.base.search.ExtendedSearchProposition.Boolean = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search.proposition.boolean',
|
||||
identifier_prefix: 'extended-search-proposition-boolean',
|
||||
operators: [
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*---------------------------------------------------------
|
||||
* OpenERP base library
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.base.view_help = function(openerp) {
|
||||
|
||||
openerp.base.ProcessView = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.HelpView = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
|
@ -2,10 +2,10 @@
|
|||
* OpenERP base library
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.base.tree = function(openerp) {
|
||||
openerp.base.view_tree = function(openerp) {
|
||||
|
||||
openerp.base.views.add('tree', 'openerp.base.TreeView');
|
||||
openerp.base.TreeView = openerp.base.Controller.extend({
|
||||
openerp.base.TreeView = openerp.base.Widget.extend({
|
||||
/**
|
||||
* Genuine tree view (the one displayed as a tree, not the list)
|
||||
*/
|
|
@ -4,84 +4,117 @@
|
|||
|
||||
openerp.base.views = function(openerp) {
|
||||
|
||||
openerp.base.ActionManager = openerp.base.Controller.extend({
|
||||
openerp.base.ActionManager = openerp.base.Widget.extend({
|
||||
// process all kind of actions
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
this.viewmanager = null;
|
||||
this.dialog_stack = [];
|
||||
this.current_dialog = null;
|
||||
// Temporary linking view_manager to session.
|
||||
// Will use controller_parent to find it when implementation will be done.
|
||||
session.action_manager = this;
|
||||
// Will use parent to find it when implementation will be done.
|
||||
this.session.action_manager = this;
|
||||
},
|
||||
/**
|
||||
* Process an action
|
||||
* Supported actions: act_window
|
||||
*/
|
||||
action_window: function() {
|
||||
},
|
||||
action_window_close: function() {
|
||||
},
|
||||
action_server: function() {
|
||||
},
|
||||
action_url: function() {
|
||||
},
|
||||
action_report: function() {
|
||||
},
|
||||
action_client: function() {
|
||||
},
|
||||
do_action: function(action, on_closed) {
|
||||
var self = this;
|
||||
action.flags = _.extend({
|
||||
sidebar : action.target != 'new',
|
||||
search_view : true,
|
||||
search_view : action.target != 'new',
|
||||
new_window : false,
|
||||
views_switcher : true,
|
||||
action_buttons : true,
|
||||
pager : true
|
||||
views_switcher : action.target != 'new',
|
||||
action_buttons : action.target != 'new',
|
||||
pager : action.target != 'new'
|
||||
}, action.flags || {});
|
||||
// instantiate the right controllers by understanding the action
|
||||
switch (action.type) {
|
||||
case 'ir.actions.act_window':
|
||||
if (!action.target && this.dialog_stack.length) {
|
||||
if (!action.target && this.current_dialog) {
|
||||
action.flags.new_window = true;
|
||||
}
|
||||
if (action.target == 'new') {
|
||||
var element_id = _.uniqueId("act_window_dialog");
|
||||
$('<div>', {id: element_id}).dialog({
|
||||
title: action.name,
|
||||
modal: true,
|
||||
width: '50%',
|
||||
height: 'auto'
|
||||
}).bind('dialogclose', function(event) {
|
||||
// When dialog is closed with ESC key or close manually, branch to act_window_close logic
|
||||
self.do_action({ type: 'ir.actions.act_window_close' });
|
||||
});
|
||||
var viewmanager = new openerp.base.ViewManagerAction(this.session, element_id, action);
|
||||
var dialog = this.current_dialog = new openerp.base.ActionDialog(this, { title: action.name, width: '90%' });
|
||||
if (on_closed) {
|
||||
dialog.close_callback = on_closed;
|
||||
}
|
||||
dialog.start(false);
|
||||
var viewmanager = dialog.viewmanager = new openerp.base.ViewManagerAction(this, dialog.element_id, action);
|
||||
viewmanager.start();
|
||||
viewmanager.on_act_window_closed.add(on_closed);
|
||||
viewmanager.is_dialog = true;
|
||||
this.dialog_stack.push(viewmanager);
|
||||
dialog.open();
|
||||
} else if (action.flags.new_window) {
|
||||
action.flags.new_window = false;
|
||||
this.rpc("/base/session/save_session_action", { the_action : action}, function(key) {
|
||||
var url = window.location.protocol + "//" + window.location.host +
|
||||
window.location.pathname + "?" + jQuery.param({ s_action : "" + key });
|
||||
window.open(url);
|
||||
if (on_closed) {
|
||||
on_closed();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.viewmanager) {
|
||||
this.viewmanager.stop();
|
||||
}
|
||||
this.viewmanager = new openerp.base.ViewManagerAction(this.session, this.element_id, action);
|
||||
this.viewmanager = new openerp.base.ViewManagerAction(this, this.element_id, action);
|
||||
this.viewmanager.start();
|
||||
}
|
||||
break;
|
||||
case 'ir.actions.act_window_close':
|
||||
var dialog = this.dialog_stack.pop();
|
||||
if (!action.special) {
|
||||
dialog.on_act_window_closed();
|
||||
}
|
||||
dialog.$element.dialog('destroy');
|
||||
dialog.stop();
|
||||
this.close_dialog();
|
||||
break;
|
||||
case 'ir.actions.server':
|
||||
this.rpc('/base/action/run', {
|
||||
action_id: action.id,
|
||||
context: {active_id: 66, active_ids: [66], active_model: 'ir.ui.menu'}
|
||||
}).then(function (action) {
|
||||
self.do_action(action, on_closed)
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log("Action manager can't handle action of type " + action.type, action);
|
||||
}
|
||||
},
|
||||
close_dialog: function() {
|
||||
if (this.current_dialog) {
|
||||
this.current_dialog.stop();
|
||||
this.current_dialog = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.ViewManager = openerp.base.Controller.extend({
|
||||
init: function(session, element_id, dataset, views) {
|
||||
this._super(session, element_id);
|
||||
openerp.base.ActionDialog = openerp.base.Dialog.extend({
|
||||
identifier_prefix: 'action_dialog',
|
||||
on_close: function() {
|
||||
this._super(this, arguments);
|
||||
if (this.close_callback) {
|
||||
this.close_callback();
|
||||
}
|
||||
},
|
||||
stop: function() {
|
||||
this._super(this, arguments);
|
||||
if (this.viewmanager) {
|
||||
this.viewmanager.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.ViewManager = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id, dataset, views) {
|
||||
this._super(parent, element_id);
|
||||
this.model = dataset.model;
|
||||
this.dataset = dataset;
|
||||
this.searchview = null;
|
||||
|
@ -90,14 +123,13 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
{return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;});
|
||||
this.views = {};
|
||||
this.flags = this.flags || {};
|
||||
this.sidebar = new openerp.base.NullSidebar();
|
||||
this.registry = openerp.base.views;
|
||||
this.is_dialog = false;
|
||||
},
|
||||
/**
|
||||
* @returns {jQuery.Deferred} initial view loading promise
|
||||
*/
|
||||
start: function() {
|
||||
this._super();
|
||||
var self = this;
|
||||
this.dataset.start();
|
||||
this.$element.html(QWeb.render("ViewManager", {"prefix": this.element_id, views: this.views_src}));
|
||||
|
@ -105,7 +137,12 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
self.on_mode_switch($(this).data('view-type'));
|
||||
});
|
||||
_.each(this.views_src, function(view) {
|
||||
self.views[view.view_type] = $.extend({}, view, {controller: null});
|
||||
self.views[view.view_type] = $.extend({}, view, {
|
||||
controller : null,
|
||||
options : _.extend({
|
||||
sidebar_id : self.element_id + '_sidebar_' + view.view_type
|
||||
}, self.flags)
|
||||
});
|
||||
});
|
||||
if (this.flags.views_switcher === false) {
|
||||
this.$element.find('.oe_vm_switch').hide();
|
||||
|
@ -129,7 +166,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
if (!view.controller) {
|
||||
// Lazy loading of views
|
||||
var controllerclass = this.registry.get_object(view_type);
|
||||
var controller = new controllerclass( this, this.session, this.element_id + "_view_" + view_type,
|
||||
var controller = new controllerclass(this, this.element_id + '_view_' + view_type,
|
||||
this.dataset, view.view_id, view.options);
|
||||
if (view.embedded_view) {
|
||||
controller.set_embedded_view(view.embedded_view);
|
||||
|
@ -183,7 +220,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
},
|
||||
/**
|
||||
* Event launched when a controller has been inited.
|
||||
*
|
||||
*
|
||||
* @param {String} view_type type of view
|
||||
* @param {String} view the inited controller
|
||||
*/
|
||||
|
@ -199,7 +236,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
if (this.searchview) {
|
||||
this.searchview.stop();
|
||||
}
|
||||
this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, search_defaults);
|
||||
this.searchview = new openerp.base.SearchView(this, this.element_id + "_search", this.dataset, view_id, search_defaults);
|
||||
if (this.flags.search_view === false) {
|
||||
this.searchview.hide();
|
||||
}
|
||||
|
@ -210,11 +247,6 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
});
|
||||
return this.searchview.start();
|
||||
},
|
||||
/**
|
||||
* Called when this view manager has been created by an action 'act_window@target=new' is closed
|
||||
*/
|
||||
on_act_window_closed : function() {
|
||||
},
|
||||
/**
|
||||
* Called when one of the view want to execute an action
|
||||
*/
|
||||
|
@ -246,45 +278,39 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
});
|
||||
|
||||
openerp.base.NullViewManager = openerp.base.generate_null_object_class(openerp.base.ViewManager, {
|
||||
init: function() {
|
||||
this._super();
|
||||
init: function(parent) {
|
||||
this._super(parent);
|
||||
if(parent)
|
||||
this.session = parent.session;
|
||||
this.action = {flags: {}};
|
||||
this.sidebar = new openerp.base.NullSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO Will move to action Manager
|
||||
openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
||||
init: function(session, element_id, action) {
|
||||
init: function(parent, element_id, action) {
|
||||
this.session = parent.session;
|
||||
var dataset;
|
||||
if (!action.res_id) {
|
||||
dataset = new openerp.base.DataSetSearch(session, action.res_model, action.context || null);
|
||||
dataset = new openerp.base.DataSetSearch(this, action.res_model, action.context || null);
|
||||
} else {
|
||||
dataset = new openerp.base.DataSetStatic(session, action.res_model, {}, [action.res_id]);
|
||||
dataset = new openerp.base.DataSetStatic(this, action.res_model, {}, [action.res_id]);
|
||||
if (action.context) {
|
||||
// TODO fme: should normalize all DataSets constructors to (session, model, context, ...)
|
||||
dataset.context = action.context;
|
||||
}
|
||||
}
|
||||
this._super(session, element_id, dataset, action.views);
|
||||
this._super(parent, element_id, dataset, action.views);
|
||||
this.action = action;
|
||||
this.flags = this.action.flags || {};
|
||||
if (action.res_model == 'board.board' && action.views.length == 1 && action.views) {
|
||||
// Not elegant but allows to avoid flickering of SearchView#do_hide
|
||||
this.flags.search_view = this.flags.pager = this.flags.sidebar = this.flags.action_buttons = false;
|
||||
}
|
||||
if (this.flags.sidebar) {
|
||||
this.sidebar = new openerp.base.Sidebar(null, this);
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
var inital_view_loaded = this._super();
|
||||
|
||||
// init sidebar
|
||||
if (this.flags.sidebar) {
|
||||
this.$element.find('.view-manager-main-sidebar').html(this.sidebar.render());
|
||||
this.sidebar.start();
|
||||
}
|
||||
|
||||
var search_defaults = {};
|
||||
_.each(this.action.context, function (value, key) {
|
||||
var match = /^search_default_(.*)$/.exec(key);
|
||||
|
@ -308,8 +334,7 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
|||
}
|
||||
},
|
||||
stop: function() {
|
||||
// should be replaced by automatic destruction implemented in BaseWidget
|
||||
this.sidebar.stop();
|
||||
// should be replaced by automatic destruction implemented in Widget
|
||||
this._super();
|
||||
},
|
||||
/**
|
||||
|
@ -336,82 +361,101 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.Sidebar = openerp.base.BaseWidget.extend({
|
||||
template: "ViewManager.sidebar",
|
||||
init: function(parent, view_manager) {
|
||||
this._super(parent, view_manager.session);
|
||||
this.view_manager = view_manager;
|
||||
this.sections = [];
|
||||
},
|
||||
set_toolbar: function(toolbar) {
|
||||
this.sections = [];
|
||||
var self = this;
|
||||
_.each([["print", "Reports"], ["action", "Actions"], ["relate", "Links"]], function(type) {
|
||||
if (toolbar[type[0]].length == 0)
|
||||
return;
|
||||
var section = {elements:toolbar[type[0]], label:type[1]};
|
||||
self.sections.push(section);
|
||||
});
|
||||
this.do_refresh(true);
|
||||
},
|
||||
do_refresh: function(new_view) {
|
||||
var view = this.view_manager.active_view;
|
||||
var the_condition = this.sections.length > 0 && _.detect(this.sections,
|
||||
function(x) {return x.elements.length > 0;}) != undefined
|
||||
&& (!new_view || view != 'list');
|
||||
|
||||
this.$element.toggleClass('open-sidebar', the_condition)
|
||||
.toggleClass('closed-sidebar', !the_condition);
|
||||
|
||||
this.$element.html(QWeb.render("ViewManager.sidebar.internal", { sidebar: this, view: view }));
|
||||
|
||||
var self = this;
|
||||
this.$element.find(".toggle-sidebar").click(function(e) {
|
||||
self.$element.toggleClass('open-sidebar closed-sidebar');
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
this.$element.find("a.oe_sidebar_action_a").click(function(e) {
|
||||
var $this = jQuery(this);
|
||||
var index = $this.attr("data-index").split('-');
|
||||
var action = self.sections[index[0]].elements[index[1]];
|
||||
action.flags = {
|
||||
new_window : true
|
||||
};
|
||||
self.session.action_manager.do_action(action);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
openerp.base.Sidebar = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
this.items = {};
|
||||
this.sections = {};
|
||||
},
|
||||
start: function() {
|
||||
this._super();
|
||||
this.do_refresh(false);
|
||||
var self = this;
|
||||
this._super(this, arguments);
|
||||
this.$element.html(QWeb.render('Sidebar'));
|
||||
this.$element.find(".toggle-sidebar").click(function(e) {
|
||||
self.do_toggle();
|
||||
});
|
||||
},
|
||||
add_toolbar: function(toolbar) {
|
||||
var self = this;
|
||||
_.each([['print', "Reports"], ['action', "Actions"], ['relate', "Links"]], function(type) {
|
||||
var items = toolbar[type[0]];
|
||||
if (items.length) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
items[i] = {
|
||||
label: items[i]['name'],
|
||||
action: items[i],
|
||||
classname: 'oe_sidebar_' + type[0]
|
||||
}
|
||||
}
|
||||
self.add_section(type[0], type[1], items);
|
||||
}
|
||||
});
|
||||
},
|
||||
add_section: function(code, name, items) {
|
||||
// For each section, we pass a name/label and optionally an array of items.
|
||||
// If no items are passed, then the section will be created as a custom section
|
||||
// returning back an element_id to be used by a custom controller.
|
||||
// Else, the section is a standard section with items displayed as links.
|
||||
// An item is a dictonary : {
|
||||
// label: label to be displayed for the link,
|
||||
// action: action to be launch when the link is clicked,
|
||||
// callback: a function to be executed when the link is clicked,
|
||||
// classname: optional dom class name for the line,
|
||||
// title: optional title for the link
|
||||
// }
|
||||
// Note: The item should have one action or/and a callback
|
||||
var self = this,
|
||||
section_id = _.uniqueId(this.element_id + '_section_' + code + '_');
|
||||
if (items) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
items[i].element_id = _.uniqueId(section_id + '_item_');
|
||||
this.items[items[i].element_id] = items[i];
|
||||
}
|
||||
}
|
||||
var $section = $(QWeb.render("Sidebar.section", {
|
||||
section_id: section_id,
|
||||
name: name,
|
||||
classname: 'oe_sidebar_' + code,
|
||||
items: items
|
||||
}));
|
||||
if (items) {
|
||||
$section.find('a.oe_sidebar_action_a').click(function() {
|
||||
var item = self.items[$(this).attr('id')];
|
||||
if (item.callback) {
|
||||
item.callback();
|
||||
}
|
||||
if (item.action) {
|
||||
item.action.flags = item.action.flags || {};
|
||||
item.action.flags.new_window = true;
|
||||
self.do_action(item.action);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
$section.appendTo(this.$element.find('div.sidebar-actions'));
|
||||
this.sections[code] = $section;
|
||||
return section_id;
|
||||
},
|
||||
do_fold: function() {
|
||||
this.$element.addClass('closed-sidebar').removeClass('open-sidebar');
|
||||
},
|
||||
do_unfold: function() {
|
||||
this.$element.addClass('open-sidebar').removeClass('closed-sidebar');
|
||||
},
|
||||
do_toggle: function() {
|
||||
this.$element.toggleClass('open-sidebar closed-sidebar');
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.NullSidebar = openerp.base.generate_null_object_class(openerp.base.Sidebar);
|
||||
|
||||
openerp.base.Export = openerp.base.Dialog.extend({
|
||||
dialog_title: "Export",
|
||||
template: 'ExportDialog',
|
||||
identifier_prefix: 'export_dialog',
|
||||
init: function (session, model, domain) {
|
||||
this._super();
|
||||
openerp.base.View = openerp.base.Widget.extend({
|
||||
set_default_options: function(options) {
|
||||
this.options = options || {};
|
||||
_.defaults(this.options, {
|
||||
// All possible views options should be defaulted here
|
||||
sidebar_id: null,
|
||||
sidebar: true
|
||||
});
|
||||
},
|
||||
start: function () {
|
||||
this._super();
|
||||
this.$element.html(this.render());
|
||||
},
|
||||
on_button_Export: function() {
|
||||
console.log("Export")
|
||||
},
|
||||
on_button_Cancel: function() {
|
||||
this.$element.dialog("close");
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.View = openerp.base.Controller.extend({
|
||||
/**
|
||||
* Fetches and executes the action identified by ``action_data``.
|
||||
*
|
||||
|
@ -423,11 +467,15 @@ openerp.base.View = openerp.base.Controller.extend({
|
|||
* @param {openerp.base.DataSet} dataset a dataset object used to communicate with the server
|
||||
* @param {openerp.base.ActionManager} action_manager object able to actually execute the action, if any is fetched
|
||||
* @param {Object} [record_id] the identifier of the object on which the action is to be applied
|
||||
* @param {Function} on_no_action callback to execute if the action does not generate any result (no new action)
|
||||
* @param {Function} on_closed callback to execute when dialog is closed or when the action does not generate any result (no new action)
|
||||
*/
|
||||
execute_action: function (action_data, dataset, action_manager, record_id, on_no_action, on_closed) {
|
||||
execute_action: function (action_data, dataset, action_manager, record_id, on_closed) {
|
||||
var self = this;
|
||||
if (action_manager.current_dialog) {
|
||||
on_closed = action_manager.current_dialog.close_callback;
|
||||
}
|
||||
var handler = function (r) {
|
||||
action_manager.close_dialog();
|
||||
var action = r.result;
|
||||
if (action && action.constructor == Object) {
|
||||
action.context = action.context || {};
|
||||
|
@ -437,29 +485,16 @@ openerp.base.View = openerp.base.Controller.extend({
|
|||
active_model: dataset.model
|
||||
});
|
||||
action.flags = {
|
||||
sidebar : false,
|
||||
search_view : false,
|
||||
views_switcher : false,
|
||||
action_buttons : false,
|
||||
pager : false
|
||||
new_window: true
|
||||
};
|
||||
action_manager.do_action(action, on_closed);
|
||||
if (self.view_manager.is_dialog && action.type != 'ir.actions.act_window_close') {
|
||||
handler({
|
||||
result : { type: 'ir.actions.act_window_close' }
|
||||
});
|
||||
}
|
||||
} else {
|
||||
on_no_action(action);
|
||||
} else if (on_closed) {
|
||||
on_closed(action);
|
||||
}
|
||||
};
|
||||
|
||||
if (action_data.special) {
|
||||
handler({
|
||||
result : { type: 'ir.actions.act_window_close', special: action_data.special }
|
||||
});
|
||||
} else {
|
||||
var context = new openerp.base.CompoundContext(dataset.context, action_data.context || {});
|
||||
if (!action_data.special) {
|
||||
var context = new openerp.base.CompoundContext(dataset.get_context(), action_data.context || {});
|
||||
switch(action_data.type) {
|
||||
case 'object':
|
||||
return dataset.call_button(action_data.name, [[record_id], context], handler);
|
||||
|
@ -468,17 +503,73 @@ openerp.base.View = openerp.base.Controller.extend({
|
|||
default:
|
||||
return dataset.exec_workflow(record_id, action_data.name, handler);
|
||||
}
|
||||
} else {
|
||||
action_manager.close_dialog();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Directly set a view to use instead of calling fields_view_get. This method must
|
||||
* be called before start(). When an embedded view is set, underlying implementations
|
||||
* of openerp.base.View must use the provided view instead of any other one.
|
||||
*
|
||||
*
|
||||
* @param embedded_view A view.
|
||||
*/
|
||||
set_embedded_view: function(embedded_view) {
|
||||
this.embedded_view = embedded_view;
|
||||
},
|
||||
set_common_sidebar_sections: function(sidebar) {
|
||||
sidebar.add_section('customize', "Customize", [
|
||||
{
|
||||
label: "Manage Views",
|
||||
callback: this.on_sidebar_manage_view,
|
||||
title: "Manage views of the current object"
|
||||
}, {
|
||||
label: "Edit Workflow",
|
||||
callback: this.on_sidebar_edit_workflow,
|
||||
title: "Manage views of the current object",
|
||||
classname: 'oe_hide oe_sidebar_edit_workflow'
|
||||
}, {
|
||||
label: "Customize Object",
|
||||
callback: this.on_sidebar_customize_object,
|
||||
title: "Manage views of the current object"
|
||||
}
|
||||
]);
|
||||
sidebar.add_section('other', "Other Options", [
|
||||
{
|
||||
label: "Import",
|
||||
callback: this.on_sidebar_import
|
||||
}, {
|
||||
label: "Export",
|
||||
callback: this.on_sidebar_export
|
||||
}, {
|
||||
label: "Translate",
|
||||
callback: this.on_sidebar_translate,
|
||||
classname: 'oe_hide oe_sidebar_translate'
|
||||
}, {
|
||||
label: "View Log",
|
||||
callback: this.on_sidebar_view_log,
|
||||
classname: 'oe_hide oe_sidebar_view_log'
|
||||
}
|
||||
]);
|
||||
},
|
||||
on_sidebar_manage_view: function() {
|
||||
console.log('Todo');
|
||||
},
|
||||
on_sidebar_edit_workflow: function() {
|
||||
console.log('Todo');
|
||||
},
|
||||
on_sidebar_customize_object: function() {
|
||||
console.log('Todo');
|
||||
},
|
||||
on_sidebar_import: function() {
|
||||
},
|
||||
on_sidebar_export: function() {
|
||||
var export_view = new openerp.base.DataExport(this, this.dataset);
|
||||
export_view.start(false);
|
||||
},
|
||||
on_sidebar_translate: function() {
|
||||
},
|
||||
on_sidebar_view_log: function() {
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -487,12 +578,6 @@ openerp.base.View = openerp.base.Controller.extend({
|
|||
*/
|
||||
openerp.base.views = new openerp.base.Registry();
|
||||
|
||||
openerp.base.ProcessView = openerp.base.Controller.extend({
|
||||
});
|
||||
|
||||
openerp.base.HelpView = openerp.base.Controller.extend({
|
||||
});
|
||||
|
||||
openerp.base.json_node_to_xml = function(node, single_quote, indent) {
|
||||
// For debugging purpose, this function will convert a json node back to xml
|
||||
// Maybe usefull for xml view editor
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<td><label for="db">Database:</label></td>
|
||||
<td>
|
||||
<t t-if="!db_list">
|
||||
<input type="text" name="db" value="trunk" autofocus="true"/>
|
||||
<input type="text" name="db" t-att-value="selected_db || ''" autofocus="true"/>
|
||||
</t>
|
||||
<t t-if="db_list">
|
||||
<select name="db">
|
||||
|
@ -87,18 +87,7 @@
|
|||
<tr>
|
||||
<td><label for="password">Password:</label></td>
|
||||
<td><input type="password" name="password"
|
||||
t-att-value="selected_password || ''"/></td>
|
||||
</tr>
|
||||
<tr t-if="has_local_storage">
|
||||
<td><label for="remember">Remember password:</label></td>
|
||||
<td class="oe_remember">
|
||||
<t t-if="remember">
|
||||
<input type="checkbox" name="remember" checked="yes"/>
|
||||
</t>
|
||||
<t t-if="!remember">
|
||||
<input type="checkbox" name="remember"/>
|
||||
</t>
|
||||
</td>
|
||||
t-att-value="selected_password || ''"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
|
@ -114,7 +103,7 @@
|
|||
<div class="oe_login_right_pane">
|
||||
<p>We think that daily job activities can be more intuitive, efficient, automated, .. and even fun.</p>
|
||||
<h3>OpenERP's vision to be:</h3>
|
||||
|
||||
|
||||
<table cellpadding="0" cellspacing="0" width="100%" style="border:none;">
|
||||
<tbody>
|
||||
<tr>
|
||||
|
@ -146,7 +135,7 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Header">
|
||||
|
@ -154,8 +143,8 @@
|
|||
<div class="company_logo" />
|
||||
</a>
|
||||
<h1 class="header_title" t-if="session.session_is_valid()">
|
||||
<span class="company">$company</span> - (<span class="database">$database</span>)<br/>
|
||||
<small class="username">$username session_id: <t t-esc="session.session_id"/></small>
|
||||
<span class="database"><t t-esc="session.db"/></span> - <t t-esc="session.login"/> <br/>
|
||||
<small class="username">rpc_session_id: <t t-esc="session.session_id"/></small>
|
||||
</h1>
|
||||
<div class="header_corner">
|
||||
<ul class="block" t-if="session.session_is_valid()">
|
||||
|
@ -243,42 +232,66 @@
|
|||
</t>
|
||||
</td>
|
||||
<td class="view-manager-main-sidebar" height="100%">
|
||||
<t t-foreach="views" t-as="view">
|
||||
<div t-attf-id="#{prefix}_sidebar_#{view.view_type}" class="sidebar-main-div closed-sidebar" style="display: none"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
<table t-name="ListView">
|
||||
<t t-name="Sidebar">
|
||||
<a class="toggle-sidebar"></a>
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-actions">
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Sidebar.section">
|
||||
<h2><t t-esc="name"/></h2>
|
||||
<div t-att-id="section_id" t-att-class="classname">
|
||||
<ul t-if="items">
|
||||
<li t-foreach="items" t-as="item" t-att-class="item.classname">
|
||||
<a class="oe_sidebar_action_a" t-att-id="item.element_id" t-att-title="item.title" href="#">
|
||||
<t t-esc="item.label"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
<table t-name="ListView" class="oe-listview-content">
|
||||
<t t-set="columns_count" t-value="visible_columns.length + (options.selectable ? 1 : 0) + (options.deletable ? 1 : 0)"/>
|
||||
<t t-set="actions_span" t-value="Math.floor((options.deletable or options.addable) ? columns_count/2 : 0)"/>
|
||||
<thead class="ui-widget-header">
|
||||
<tr>
|
||||
<th t-if="actions_span" t-att-colspan="actions_span"
|
||||
class="oe-actions">
|
||||
<t t-if="flags.action_buttons !== false">
|
||||
<button type="button" id="oe-list-add"
|
||||
t-if="options.addable">
|
||||
<t t-esc="options.addable"/>
|
||||
</button>
|
||||
<button type="button" id="oe-list-delete"
|
||||
t-if="options.selectable and options.deletable">
|
||||
Delete
|
||||
</button>
|
||||
</t>
|
||||
</th>
|
||||
<th t-att-colspan="columns_count - actions_span"
|
||||
class="oe-list-pager">
|
||||
<t t-if="flags.pager !== false">
|
||||
<button type="button" data-pager-action="first">First</button>
|
||||
<button type="button" data-pager-action="previous"
|
||||
><<</button>
|
||||
<tr t-if="options.action_buttons !== false or options.pager !== false">
|
||||
<th t-att-colspan="columns_count">
|
||||
<table>
|
||||
<tr>
|
||||
<td t-if="options.action_buttons !== false" class="oe-actions">
|
||||
<button type="button" class="oe-list-add"
|
||||
t-if="options.addable">
|
||||
<t t-esc="options.addable"/>
|
||||
</button>
|
||||
<button type="button" class="oe-list-delete"
|
||||
t-if="options.selectable and options.deletable">
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
<th t-if="options.pager !== false" class="oe-list-pager">
|
||||
<button type="button" disabled="disabled"
|
||||
data-pager-action="first">First</button>
|
||||
<button type="button" disabled="disabled"
|
||||
data-pager-action="previous"
|
||||
><</button>
|
||||
|
||||
<span class="oe-pager-first">1</span>
|
||||
to <span class="oe-pager-last">1</span>
|
||||
of <span class="oe-pager-total">1</span>
|
||||
<span class="oe-pager-state">
|
||||
</span>
|
||||
|
||||
<button type="button" data-pager-action="next">>></button>
|
||||
<button type="button" data-pager-action="last">Last</button>
|
||||
</t>
|
||||
<button type="button" disabled="disabled"
|
||||
data-pager-action="next">></button>
|
||||
<button type="button" disabled="disabled"
|
||||
data-pager-action="last">Last</button>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
</th>
|
||||
</tr>
|
||||
<tr t-if="options.header">
|
||||
|
@ -287,24 +300,22 @@
|
|||
<t t-esc="column.string"/>
|
||||
</th>
|
||||
</t>
|
||||
<th t-if="options.selectable"/>
|
||||
<th t-if="options.selectable" width="1"/>
|
||||
<t t-foreach="columns" t-as="column">
|
||||
<th t-if="!column.meta and column.invisible !== '1'" t-att-data-id="column.id"
|
||||
t-att-class="((options.sortable and column.tag !== 'button') ? 'oe-sortable' : null)">
|
||||
<t t-if="column.tag !== 'button'">
|
||||
<t t-esc="column.string"/>
|
||||
<span t-att-class="(fields_view.sorted.field === column.id) ? ('ui-icon' + (fields_view.sorted.reversed ? ' ui-icon-triangle-1-n' : ' ui-icon-triangle-1-s')) : ''"/>
|
||||
</t>
|
||||
<t t-if="column.tag !== 'button'"
|
||||
><t t-esc="column.string"/></t>
|
||||
</th>
|
||||
</t>
|
||||
<th t-if="options.deletable"/>
|
||||
<th t-if="options.deletable" width="1"/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="ui-widget-header">
|
||||
<tr>
|
||||
<td t-if="options.selectable"/>
|
||||
<td t-foreach="aggregate_columns" t-as="column" class="oe-list-footer oe-number"
|
||||
t-att-data-field="column.field" t-att-title="column.label">
|
||||
t-att-data-field="column.id" t-att-title="column.label">
|
||||
</td>
|
||||
<td t-if="options.deletable"/>
|
||||
</tr>
|
||||
|
@ -322,10 +333,10 @@
|
|||
t-att-data-index="row_index">
|
||||
<t t-foreach="columns" t-as="column">
|
||||
<td t-if="column.meta">
|
||||
|
||||
|
||||
</td>
|
||||
</t>
|
||||
<th t-if="options.selectable" class="oe-record-selector">
|
||||
<th t-if="options.selectable" class="oe-record-selector" width="1">
|
||||
<input type="checkbox"/>
|
||||
</th>
|
||||
<t t-foreach="columns" t-as="column">
|
||||
|
@ -333,23 +344,10 @@
|
|||
<td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help"
|
||||
t-att-class="'oe-field-cell' + (align ? ' oe-number' : '')"
|
||||
t-att-data-field="column.id">
|
||||
<t t-set="attrs" t-value="column.attrs_for(row.data)"/>
|
||||
<t t-if="!attrs.invisible">
|
||||
<t t-set="is_button" t-value="column.tag === 'button'"/>
|
||||
<!-- TODO: get correct widget from form -->
|
||||
<t t-if="!is_button and row['data'][column.id].value !== false">
|
||||
<t t-set="value" t-value="row['data'][column.id].value"/>
|
||||
<t t-esc="value instanceof Array ? value[1] : value"/>
|
||||
</t>
|
||||
<button type="button" t-att-title="column.string"
|
||||
t-if="is_button">
|
||||
<img t-att-src="'/base/static/src/img/icons/' + column.icon + '.png'"
|
||||
t-att-alt="column.string"/>
|
||||
</button>
|
||||
</t>
|
||||
<t t-raw="render_cell(row.data, column)"/>
|
||||
</td>
|
||||
</t>
|
||||
<td t-if="options.deletable" class='oe-record-delete'>
|
||||
<td t-if="options.deletable" class='oe-record-delete' width="1">
|
||||
<button type="button" name="delete">♻</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -357,9 +355,9 @@
|
|||
<t t-raw="frame.render()"/>
|
||||
</t>
|
||||
<t t-name="FormView">
|
||||
<h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/></h2>
|
||||
<div class="oe_form_header" t-att-id="view.element_id + '_header'">
|
||||
<div class="oe_form_buttons" t-if="view.flags.action_buttons !== false">
|
||||
<h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/> <button class="oe_get_xml_view">xml</button></h2>
|
||||
<div class="oe_form_buttons" t-if="view.options.action_buttons !== false">
|
||||
<!--<button type="button" class="oe_form_button_save">
|
||||
<span class="oe_form_on_update">Save</span>
|
||||
<span class="oe_form_on_create">Create</span>
|
||||
|
@ -371,7 +369,7 @@
|
|||
<!--<button type="button" class="oe_form_button_cancel">Cancel</button>-->
|
||||
<button type="button" class="oe_form_button_new">New</button>
|
||||
</div>
|
||||
<div class="oe_form_pager" t-if="view.flags.pager !== false">
|
||||
<div class="oe_form_pager" t-if="view.options.pager !== false">
|
||||
<button type="button" data-pager-action="first">First</button>
|
||||
<button type="button" data-pager-action="previous"><<</button>
|
||||
|
||||
|
@ -384,21 +382,20 @@
|
|||
<t t-raw="frame.render()"/>
|
||||
</t>
|
||||
<t t-name="FormView.sidebar.attachments">
|
||||
<h2>Attachments</h2>
|
||||
<div class="oe-sidebar-attachments-toolbar">
|
||||
<div class="oe-binary-file-set" style="float: right">
|
||||
<form class="oe-binary-form" t-attf-target="#{element_id}_iframe"
|
||||
method="post" enctype="multipart/form-data" action="/base/binary/upload_attachment">
|
||||
<input type="hidden" name="session_id" t-att-value="session.session_id"/>
|
||||
<input type="hidden" name="callback" t-attf-value="#{element_id}_iframe"/>
|
||||
<input type="hidden" name="model" t-att-value="dataset.model"/>
|
||||
<input type="hidden" name="id" t-att-value="datarecord.id"/>
|
||||
<input type="hidden" name="model" t-att-value="view.dataset.model"/>
|
||||
<input type="hidden" name="id" t-att-value="view.datarecord.id"/>
|
||||
<button class="button" type="button">
|
||||
<img src="/base/static/src/img/throbber.gif" width="16" height="16" style="display: none"/>
|
||||
<span>Add</span>
|
||||
</button>
|
||||
<input type="file" class="oe-binary-file" name="ufile" title="Add attachment"
|
||||
t-att-onclick="datarecord.id ? null : 'alert(\'No record selected ! You can only attach to existing record.\'); return false;'"/>
|
||||
t-att-onclick="view.datarecord.id ? null : 'alert(\'No record selected ! You can only attach to existing record.\'); return false;'"/>
|
||||
</form>
|
||||
<iframe t-attf-id="#{element_id}_iframe" t-attf-name="#{element_id}_iframe" style="display: none"> </iframe>
|
||||
</div>
|
||||
|
@ -408,7 +405,7 @@
|
|||
<li t-foreach="attachments" t-as="attachment">
|
||||
<t t-if="attachment.type == 'binary'" t-set="attachment.url" t-value="'/base/binary/saveas?session_id='
|
||||
+ session.session_id + '&model=ir.attachment&id=' + attachment.id
|
||||
+ '&field=datas' + '&fieldname=name' + '&t=' + (new Date().getTime())"/>
|
||||
+ '&field=datas&fieldname=name&t=' + (new Date().getTime())"/>
|
||||
<a class="oe-sidebar-attachments-link" t-att-href="attachment.url" target="_blank">
|
||||
<t t-esc="attachment.name"/>
|
||||
</a>
|
||||
|
@ -441,18 +438,21 @@
|
|||
</t>
|
||||
<t t-name="WidgetNotebook">
|
||||
<ul>
|
||||
<li t-foreach="widget.pages" t-as="page">
|
||||
<a t-att-href="'#' + widget.element_id + '-' + page_index">
|
||||
<li t-foreach="widget.pages" t-as="page" t-att-id="page.element_tab_id">
|
||||
<a t-att-href="'#' + page.element_id">
|
||||
<t t-esc="page.string"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<t t-foreach="widget.pages" t-as="page">
|
||||
<div t-att-id="widget.element_id + '-' + page_index">
|
||||
<t t-raw="page.render()"/>
|
||||
</div>
|
||||
<t t-raw="page.render()"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="WidgetNotebookPage">
|
||||
<div t-att-id="widget.element_id">
|
||||
<t t-call="WidgetFrame"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="WidgetSeparator">
|
||||
<div t-att-class="'separator ' + (widget.node.attrs.orientation || 'horizontal')">
|
||||
<t t-esc="widget.string"/>
|
||||
|
@ -526,9 +526,9 @@
|
|||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
style="width: 100%">
|
||||
<t t-foreach="widget.field.selection" t-as="options">
|
||||
<option t-att-value="options[0]">
|
||||
<t t-esc="options[1]"/>
|
||||
<t t-foreach="widget.field_index" t-as="options">
|
||||
<option t-att-value="options.ikey">
|
||||
<t t-esc="options.label"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
|
@ -541,9 +541,9 @@
|
|||
<span class="oe-m2o-cm-button" t-att-id="widget.name + '_open'">
|
||||
<img src="/base/static/src/img/icons/gtk-index.png"/></span>
|
||||
<div t-att-id="widget.cm_id" class="contextMenu" style="display:none"><ul>
|
||||
<li t-att-id="widget.cm_id + '_search'">Search</li>
|
||||
<li t-att-id="widget.cm_id + '_create'">Create New</li>
|
||||
<li t-att-id="widget.cm_id + '_open'" style="color:grey">Open</li>
|
||||
<li t-att-id="widget.cm_id + '_open'" style="color:grey">Open...</li>
|
||||
<li t-att-id="widget.cm_id + '_create'">Create...</li>
|
||||
<li t-att-id="widget.cm_id + '_search'">Search...</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
</t>
|
||||
|
@ -685,14 +685,28 @@
|
|||
<input type="reset" value="Clear"/>
|
||||
<button class="oe_search-view-custom-filter-btn"><span>Advanced Filter</span></button>
|
||||
<select class="oe_search-view-filters-management">
|
||||
<option value="_filters">-- Filters --</option>
|
||||
<option value="_actions">-- Actions --</option>
|
||||
<option value="save_filter">Save Filter</option>
|
||||
<option value="manage_filters">Manage Filters</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</t>
|
||||
<t t-name="SearchView.managed-filters">
|
||||
<option value="_filters">-- Filters --</option>
|
||||
<t t-set="i" t-value="0"/>
|
||||
<t t-foreach="filters" t-as="filter">
|
||||
<option t-att-value="'get:' + i"><t t-esc="filter.name"/></option>
|
||||
<t t-set="i" t-value="i+1"/>
|
||||
</t>
|
||||
<option value="_actions">-- Actions --</option>
|
||||
<option value="save_filter">Save Filter</option>
|
||||
<option value="manage_filters">Manage Filters</option>
|
||||
</t>
|
||||
<t t-name="SearchView.managed-filters.add">
|
||||
<div>
|
||||
<p>Filter Name:</p>
|
||||
<input type="text"/>
|
||||
<p>(Any existing filter with the same name will be replaced)</p>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="SearchView.render_lines">
|
||||
<table class="oe-searchview-render-line" border="0" cellspacing="0" cellpadding="0"
|
||||
t-foreach="lines" t-as="line">
|
||||
|
@ -803,11 +817,11 @@
|
|||
<t t-name="SearchView.extended_search.group">
|
||||
<div t-att-id="element_id" class="searchview_extended_group">
|
||||
<select class="searchview_extended_group_choice">
|
||||
<option value="all">All the following conditions must match</option>
|
||||
<option value="any">Any of the following conditions must match</option>
|
||||
<option value="all">All the following conditions must match</option>
|
||||
<option value="none">None of the following conditions must match</option>
|
||||
</select>
|
||||
<a class="searchview_extended_delete_group"
|
||||
<a class="searchview_extended_delete_group"
|
||||
href="javascript:void(0)"><span></span></a>
|
||||
<div class="searchview_extended_propositions_list">
|
||||
</div>
|
||||
|
@ -829,7 +843,7 @@
|
|||
<select class="searchview_extended_prop_op"/>
|
||||
<span class="searchview_extended_prop_value"/>
|
||||
<a class="searchview_extended_delete_prop"
|
||||
href="javascript:void(0)"><span></span></a>
|
||||
href="javascript:void(0)"><span> </span></a>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="SearchView.extended_search.proposition.char">
|
||||
|
@ -856,29 +870,6 @@
|
|||
</t>
|
||||
</select>
|
||||
</t>
|
||||
<t t-name="ViewManager.sidebar">
|
||||
<div t-att-id="element_id" class="sidebar-main-div closed-sidebar">
|
||||
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="ViewManager.sidebar.internal">
|
||||
<a class="toggle-sidebar"></a>
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-attachments" t-if="view == 'form'"> </div>
|
||||
<div class="sidebar-actions">
|
||||
<t t-foreach="sidebar.sections" t-as="section" t-if="section.elements.length">
|
||||
<h2><t t-esc="section.label"/></h2>
|
||||
<ul>
|
||||
<li t-foreach="section.elements" t-as="element">
|
||||
<a class="oe_sidebar_action_a" t-attf-data-index="#{section_index}-#{element_index}" href="#">
|
||||
<t t-esc="element.name"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="DialogWarning">
|
||||
<table cellspacing="0" cellpadding="0" border="0" class="oe-dialog-warning">
|
||||
<tr>
|
||||
|
@ -886,7 +877,9 @@
|
|||
<td>
|
||||
<p>
|
||||
<t t-js="d">
|
||||
d.html_error = context.engine.tools.html_escape(d.error.data.fault_code).replace(/\n/g, '<br/>');
|
||||
var message = d.message ? d.message : d.error.data.fault_code;
|
||||
d.html_error = context.engine.tools.html_escape(message)
|
||||
.replace(/\n/g, '<br/>');
|
||||
</t>
|
||||
<t t-raw="html_error"/>
|
||||
</p>
|
||||
|
@ -901,9 +894,19 @@
|
|||
</t>
|
||||
<t t-name="SelectCreatePopup">
|
||||
<div t-att-id="element_id">
|
||||
<div t-att-id="element_id + '_search'"></div>
|
||||
<div t-att-id="element_id + '_view_list'"></div>
|
||||
<div t-att-id="element_id + '_view_form'"></div>
|
||||
<table style="width:100%">
|
||||
<tr style="width:100%">
|
||||
<td style="width:100%">
|
||||
<div t-att-id="element_id + '_search'" style="width:100%"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="width:100%">
|
||||
<td style="width:100%">
|
||||
<div t-att-id="element_id + '_view_list'" style="width:100%"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div t-att-id="element_id + '_view_form'" style="width:100%"></div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="SelectCreatePopup.search.buttons">
|
||||
|
@ -914,7 +917,15 @@
|
|||
<button type="button" class="oe_selectcreatepopup-form-save">Save</button>
|
||||
<button type="button" class="oe_selectcreatepopup-form-close">Close</button>
|
||||
</t>
|
||||
|
||||
<t t-name="FormOpenPopup">
|
||||
<div t-att-id="element_id">
|
||||
<div t-att-id="element_id + '_view_form'" style="width:100%"></div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="FormOpenPopup.form.buttons">
|
||||
<button type="button" class="oe_formopenpopup-form-save">Save</button>
|
||||
<button type="button" class="oe_formopenpopup-form-close">Close</button>
|
||||
</t>
|
||||
<t t-name="ListView.row.frame" t-extend="WidgetFrame">
|
||||
<t t-jquery="tr">
|
||||
$(document.createElement('t'))
|
||||
|
@ -933,4 +944,145 @@
|
|||
.unwrap();
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ExportView">
|
||||
<a id="exportview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Export</a>
|
||||
</t>
|
||||
|
||||
<t t-name="ExportTreeView">
|
||||
<table class="view" style="background-color: #F3F3F3;">
|
||||
<tr>
|
||||
<td align="left">
|
||||
This wizard will export all data that matches the current search criteria to a CSV file.
|
||||
You can export all data or only the fields that can be reimported after modification.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td class="label"><label>Export Type:</label></td>
|
||||
<td>
|
||||
<select id="import_compat" name="import_compat">
|
||||
<option value="1">Import Compatible Export</option>
|
||||
<option value="0">Export all Data</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="label"><label>Export Format</label></td>
|
||||
<td>
|
||||
<select id="export_format" name="export_format">
|
||||
<option value="csv">CSV</option>
|
||||
<option value="xls">Excel</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<table class="oe_export_fields_selector_export">
|
||||
<tr>
|
||||
<th class="oe_view_title" valign="bottom">Available fields</th>
|
||||
<th class="oe_view_title"></th>
|
||||
<th class="oe_view_title">Fields to export
|
||||
<a style="color: blue; text-decoration: none;" href="#" id="export_new_list">Save fields list</a>
|
||||
<div id="savenewlist"></div>
|
||||
<div id="ExistsExportList"></div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="oe_export_fields_selector_left">
|
||||
<div id="left_field_panel">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<table class="oe_export_fields_selector_center">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<button id="add_field" class="oe_export_button_export">Add</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<button id="remove_field" class="oe_export_button_export">Remove</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<button id="remove_all_field" class="oe_export_button_export">Remove All</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="oe_export_fields_selector_right">
|
||||
<select name="fields_list" id="fields_list" multiple="multiple"></select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
|
||||
<t t-name="ExportTreeView-Secondary">
|
||||
<table id="field-tree-structure" class="oe_export_fields_selector_export" cellspacing="0" cellpadding="0">
|
||||
<tr><th class="oe_export_tree_header"> Name </th></tr>
|
||||
<t t-call="ExportTreeView-Secondary.children"/>
|
||||
</table>
|
||||
</t>
|
||||
<t t-name="ExportTreeView-Secondary.children">
|
||||
<t t-foreach="fields" t-as="field" >
|
||||
<tr t-att-id="'treerow-' + field.id" class="oe_export_row">
|
||||
<td>
|
||||
<table class="tree_grid" border="0">
|
||||
<tr class="oe_export_row">
|
||||
<t t-foreach="(field.id).split('/')" t-as="level" >
|
||||
<t t-if="(field.id).split('/')[0] != level">
|
||||
<td width="18">&nbsp;</td>
|
||||
</t>
|
||||
</t>
|
||||
<td valign="top" align="left" style="cursor: pointer;" width="18">
|
||||
<t t-if="(field.children).length >= 1">
|
||||
<t t-if="(field.id).split('/').length != 3">
|
||||
<img t-att-id="'parentimg-' + field.id" src="/base/static/src/img/expand.gif" width="16" height="16" border="0"/>
|
||||
</t>
|
||||
</t>
|
||||
</td>
|
||||
<td id="tree-column" valign="middle" align="left" style="cursor: pointer;">
|
||||
<a t-att-id="'export-' + field.id" t-att-string="field.string" href="javascript: void(0);" style="text-decoration: none;">
|
||||
<t t-esc="field.string"/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ExportNewList">
|
||||
<tr>
|
||||
<th><label>Save as:</label></th>
|
||||
<td><input size="10" type="text" id="savelist_name"/></td>
|
||||
<td><button class="oe_export_button_export" id="add_export_list">Ok</button></td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-name="Exists.ExportList">
|
||||
<tr><th align="right"><label >Saved exports:</label></th></tr>
|
||||
<tr align="left">
|
||||
<td>
|
||||
<select id="saved_export_list" style="width: 100%;">
|
||||
<option></option>
|
||||
<t t-foreach="existing_exports" t-as="export">
|
||||
<option t-att-value="export.id"><t t-esc="export.name"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</td>
|
||||
<td><button class="oe_export_button_export" id="delete_export_list">Delete</button></td>
|
||||
</tr>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
|
@ -18,15 +18,6 @@ $(document).ready(function () {
|
|||
}
|
||||
}};
|
||||
|
||||
var fuck_that_shit = {
|
||||
action: {
|
||||
flags: {}
|
||||
},
|
||||
sidebar: {
|
||||
set_toolbar: function () {}
|
||||
}
|
||||
};
|
||||
|
||||
var openerp;
|
||||
module("ListView", {
|
||||
setup: function () {
|
||||
|
@ -42,8 +33,7 @@ $(document).ready(function () {
|
|||
|
||||
test('render selection checkboxes', 2, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
fuck_that_shit, null,
|
||||
'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
||||
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
|
@ -60,8 +50,7 @@ $(document).ready(function () {
|
|||
});
|
||||
test('render no checkbox if selectable=false', 1, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
fuck_that_shit, null,
|
||||
'qunit-fixture', {model: null, ids: [null, null, null], index: 0}, false,
|
||||
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0}, false,
|
||||
{selectable: false});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
@ -75,8 +64,7 @@ $(document).ready(function () {
|
|||
});
|
||||
test('select a bunch of records', 2, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
fuck_that_shit, null, 'qunit-fixture',
|
||||
{model: null, ids: [1, 2, 3], index: 0});
|
||||
null, 'qunit-fixture', {model: null, ids: [1, 2, 3], index: 0});
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
listview.do_fill_table({records: [
|
||||
|
@ -94,8 +82,7 @@ $(document).ready(function () {
|
|||
});
|
||||
test('render deletion button if list is deletable', 1, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
fuck_that_shit, null, 'qunit-fixture',
|
||||
{model: null, ids: [null, null, null], index: 0});
|
||||
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
|
@ -112,7 +99,7 @@ $(document).ready(function () {
|
|||
2, function () {
|
||||
var deleted;
|
||||
var listview = new openerp.base.ListView(
|
||||
fuck_that_shit, null, 'qunit-fixture',
|
||||
null, 'qunit-fixture',
|
||||
{model: null, unlink: function (ids) {
|
||||
deleted = ids;
|
||||
}, ids: [1, 2, 3], index: 0});
|
||||
|
@ -132,7 +119,7 @@ $(document).ready(function () {
|
|||
test('multiple records deletion', 1, function () {
|
||||
var deleted;
|
||||
var listview = new openerp.base.ListView(
|
||||
fuck_that_shit, null, 'qunit-fixture',
|
||||
null, 'qunit-fixture',
|
||||
{model: null, unlink: function (ids) {
|
||||
deleted = ids;
|
||||
}, ids: [1, 2, 3], index: 0});
|
||||
|
@ -149,7 +136,7 @@ $(document).ready(function () {
|
|||
listview.$element.find('tbody th input:eq(1)')
|
||||
.attr('checked', true);
|
||||
|
||||
listview.$element.find('#oe-list-delete').click();
|
||||
listview.$element.find('.oe-list-delete').click();
|
||||
deepEqual(deleted, [2, 3]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,47 +6,6 @@ to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
|||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
dhtmlx = function (B) {
|
||||
for (var A in B) {
|
||||
dhtmlx[A] = B[A]
|
||||
}
|
||||
return dhtmlx
|
||||
};
|
||||
dhtmlx.extend_api = function (A, D, C) {
|
||||
var B = window[A];
|
||||
if (!B) {
|
||||
return
|
||||
}
|
||||
window[A] = function (G) {
|
||||
if (G && typeof G == "object" && !G.tagName && !(G instanceof Array)) {
|
||||
var F = B.apply(this, (D._init ? D._init(G) : arguments));
|
||||
for (var E in dhtmlx) {
|
||||
if (D[E]) {
|
||||
this[D[E]](dhtmlx[E])
|
||||
}
|
||||
}
|
||||
for (var E in G) {
|
||||
if (D[E]) {
|
||||
this[D[E]](G[E])
|
||||
} else {
|
||||
if (E.indexOf("on") == 0) {
|
||||
this.attachEvent(E, G[E])
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var F = B.apply(this, arguments)
|
||||
}
|
||||
if (D._patch) {
|
||||
D._patch(this)
|
||||
}
|
||||
return F || this
|
||||
};
|
||||
window[A].prototype = B.prototype;
|
||||
if (C) {
|
||||
dhtmlXHeir(window[A].prototype, C)
|
||||
}
|
||||
};
|
||||
dhtmlxAjax = {
|
||||
get: function (A, C) {
|
||||
var B = new dtmlXMLLoaderObject(true);
|
||||
|
@ -3732,4 +3691,4 @@ This software is allowed to use under GPL or you need to obtain Commercial or En
|
|||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -1,42 +1,11 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
|
||||
dhtmlx=function(obj){
|
||||
for (var a in obj) dhtmlx[a]=obj[a];
|
||||
return dhtmlx; //simple singleton
|
||||
};
|
||||
dhtmlx.extend_api=function(name,map,ext){
|
||||
var t = window[name];
|
||||
if (!t) return; //component not defined
|
||||
window[name]=function(obj){
|
||||
if (obj && typeof obj == "object" && !obj.tagName && !(obj instanceof Array)){
|
||||
var that = t.apply(this,(map._init?map._init(obj):arguments));
|
||||
//global settings
|
||||
for (var a in dhtmlx)
|
||||
if (map[a]) this[map[a]](dhtmlx[a]);
|
||||
//local settings
|
||||
for (var a in obj){
|
||||
if (map[a]) this[map[a]](obj[a]);
|
||||
else if (a.indexOf("on")==0){
|
||||
this.attachEvent(a,obj[a]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
var that = t.apply(this,arguments);
|
||||
if (map._patch) map._patch(this);
|
||||
return that||this;
|
||||
};
|
||||
window[name].prototype=t.prototype;
|
||||
if (ext)
|
||||
dhtmlXHeir(window[name].prototype,ext);
|
||||
};
|
||||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
dhtmlxAjax={
|
||||
get:function(url,callback){
|
||||
var t=new dtmlXMLLoaderObject(true);
|
||||
|
@ -908,7 +877,7 @@ dhtmlxEventable=function(obj){
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @desc: constructor, data processor object
|
||||
* @param: serverProcessorURL - url used for update
|
||||
|
@ -1489,7 +1458,7 @@ dataProcessor.prototype={
|
|||
|
||||
};
|
||||
|
||||
//(c)dhtmlx ltd. www.dhtmlx.com
|
||||
//(c)dhtmlx ltd. www.dhtmlx.com
|
||||
dataProcessor.prototype._o_init = dataProcessor.prototype.init;
|
||||
dataProcessor.prototype.init=function(obj){
|
||||
this._console=this._console||this._createConsole();
|
||||
|
@ -1654,7 +1623,7 @@ dataProcessor.wrap("afterUpdateCallback",function(sid,tid,action){
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
dhx_sort[index]=direction
|
||||
dhx_filter[index]=mask
|
||||
|
@ -1792,7 +1761,7 @@ if (window.dataProcessor){
|
|||
dhtmlxError.catchError("LoadXML",function(a,b,c){
|
||||
alert(c[0].responseText);
|
||||
});
|
||||
|
||||
|
||||
window.dhtmlXScheduler=window.scheduler={version:2.2};
|
||||
dhtmlxEventable(scheduler);
|
||||
scheduler.init=function(id,date,mode){
|
||||
|
@ -2434,7 +2403,7 @@ scheduler.getLabel = function(property, key) {
|
|||
}
|
||||
}
|
||||
return "";
|
||||
};
|
||||
};
|
||||
scheduler.date={
|
||||
date_part:function(date){
|
||||
date.setHours(0);
|
||||
|
@ -2568,7 +2537,7 @@ scheduler.date={
|
|||
return this.getISOWeek(ndate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
scheduler.locale={
|
||||
date:{
|
||||
month_full:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
||||
|
@ -2609,7 +2578,7 @@ scheduler.locale={
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
%e Day of the month without leading zeros (01..31)
|
||||
%d Day of the month, 2 digits with leading zeros (01..31)
|
||||
|
@ -2715,7 +2684,7 @@ scheduler.init_templates=function(){
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
scheduler.uid=function(){
|
||||
if (!this._seed) this._seed=(new Date).valueOf();
|
||||
return this._seed++;
|
||||
|
@ -3260,7 +3229,7 @@ scheduler.getEvents = function(from,to){
|
|||
result.push(ev);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
||||
scheduler._loaded={};
|
||||
scheduler._load=function(url,from){
|
||||
url=url||this._load_url;
|
||||
|
@ -3445,7 +3414,7 @@ scheduler.attachEvent("onXLE",function(){
|
|||
this.config.show_loading=true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
scheduler.ical={
|
||||
parse:function(str){
|
||||
var data = str.match(RegExp(this.c_start+"[^\f]*"+this.c_end,""));
|
||||
|
@ -3510,7 +3479,7 @@ scheduler.ical={
|
|||
e_start:"BEGIN:VEVENT",
|
||||
e_end:"END:VEVENT",
|
||||
c_end:"END:VCALENDAR"
|
||||
};
|
||||
};
|
||||
scheduler.form_blocks={
|
||||
textarea:{
|
||||
render:function(sns){
|
||||
|
@ -3850,7 +3819,7 @@ scheduler._get_lightbox=function(){
|
|||
}
|
||||
return this._lightbox;
|
||||
}
|
||||
scheduler._lightbox_template="<div class='dhx_cal_ltitle'><span class='dhx_mark'> </span><span class='dhx_time'></span><span class='dhx_title'></span></div><div class='dhx_cal_larea'></div><div class='dhx_btn_set'><div class='dhx_save_btn'></div><div> </div></div><div class='dhx_btn_set'><div class='dhx_cancel_btn'></div><div> </div></div><div class='dhx_btn_set' style='float:right;'><div class='dhx_delete_btn'></div><div> </div></div>";
|
||||
scheduler._lightbox_template="<div class='dhx_cal_ltitle'><span class='dhx_mark'> </span><span class='dhx_time'></span><span class='dhx_title'></span></div><div class='dhx_cal_larea'></div><div class='dhx_btn_set'><div class='dhx_save_btn'></div><div> </div></div><div class='dhx_btn_set'><div class='dhx_cancel_btn'></div><div> </div></div><div class='dhx_btn_set' style='float:right;'><div class='dhx_delete_btn'></div><div> </div></div>";
|
||||
scheduler._dp_init=function(dp){
|
||||
dp._methods=["setEventTextStyle","","changeEventId","deleteEvent"];
|
||||
|
||||
|
@ -3928,4 +3897,4 @@ scheduler._update_callback = function(upd,id){
|
|||
data.end_date = scheduler.templates.xml_date(data.end_date);
|
||||
|
||||
scheduler.addEvent(data);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,33 +1,3 @@
|
|||
dhtmlx=function(obj){
|
||||
for (var a in obj) dhtmlx[a]=obj[a];
|
||||
return dhtmlx; //simple singleton
|
||||
};
|
||||
dhtmlx.extend_api=function(name,map,ext){
|
||||
var t = window[name];
|
||||
if (!t) return; //component not defined
|
||||
window[name]=function(obj){
|
||||
if (obj && typeof obj == "object" && !obj.tagName && !(obj instanceof Array)){
|
||||
var that = t.apply(this,(map._init?map._init(obj):arguments));
|
||||
//global settings
|
||||
for (var a in dhtmlx)
|
||||
if (map[a]) this[map[a]](dhtmlx[a]);
|
||||
//local settings
|
||||
for (var a in obj){
|
||||
if (map[a]) this[map[a]](obj[a]);
|
||||
else if (a.indexOf("on")==0){
|
||||
this.attachEvent(a,obj[a]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
var that = t.apply(this,arguments);
|
||||
if (map._patch) map._patch(this);
|
||||
return that||this;
|
||||
};
|
||||
window[name].prototype=t.prototype;
|
||||
if (ext)
|
||||
dhtmlXHeir(window[name].prototype,ext);
|
||||
};
|
||||
|
||||
dhtmlxAjax={
|
||||
get:function(url,callback){
|
||||
var t=new dtmlXMLLoaderObject(true);
|
||||
|
|
|
@ -5,11 +5,10 @@
|
|||
openerp.base_calendar = function(openerp) {
|
||||
QWeb.add_template('/base_calendar/static/src/xml/base_calendar.xml');
|
||||
openerp.base.views.add('calendar', 'openerp.base_calendar.CalendarView');
|
||||
openerp.base_calendar.CalendarView = openerp.base.Controller.extend({
|
||||
openerp.base_calendar.CalendarView = openerp.base.View.extend({
|
||||
// Dhtmlx scheduler ?
|
||||
init: function(view_manager, session, element_id, dataset, view_id){
|
||||
this._super(session, element_id);
|
||||
this.view_manager = view_manager;
|
||||
init: function(parent, element_id, dataset, view_id) {
|
||||
this._super(parent, element_id);
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
|
@ -271,7 +270,6 @@ openerp.base_calendar.CalendarView = openerp.base.Controller.extend({
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
do_search: function(domains, contexts, groupbys) {
|
||||
var self = this;
|
||||
this.rpc('/base/session/eval_domain_and_context', {
|
||||
|
@ -287,7 +285,6 @@ openerp.base_calendar.CalendarView = openerp.base.Controller.extend({
|
|||
});
|
||||
});
|
||||
},
|
||||
|
||||
do_show: function () {
|
||||
this.$element.show();
|
||||
},
|
||||
|
@ -340,12 +337,13 @@ openerp.base_calendar.CalendarView = openerp.base.Controller.extend({
|
|||
}
|
||||
}
|
||||
});
|
||||
var action_manager = new openerp.base.ActionManager(this.session, element_id);
|
||||
action_manager.start();
|
||||
action_manager.do_action(action);
|
||||
//var action_manager = new openerp.base.ActionManager(this.session, element_id);
|
||||
//action_manager.start();
|
||||
//action_manager.do_action(action);
|
||||
this.do_action(action);
|
||||
|
||||
//Default_get
|
||||
if(!event_id) action_manager.viewmanager.dataset.index = null;
|
||||
if(!event_id) this.dataset.index = null;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -7,14 +7,18 @@
|
|||
}
|
||||
.openerp .oe-dashboard-action {
|
||||
margin: 0 0.5em 0.5em 0;
|
||||
padding: 2px;
|
||||
}
|
||||
.openerp .oe-dashboard-action:hover {
|
||||
border: 1px dashed #ccc;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.openerp .oe-dashboard-action .oe-dashboard-action-header {
|
||||
margin: 0.3em;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 0.2em
|
||||
font-size: 125%;
|
||||
font-weight: bold;
|
||||
}
|
||||
.openerp a.oe-dashboard-action-rename {
|
||||
float: left;
|
||||
padding-right: 4px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
|
@ -43,7 +47,7 @@
|
|||
}
|
||||
|
||||
.openerp .oe-dashboard-action .oe-dashboard-action-content {
|
||||
padding: 0.4em;
|
||||
/*padding: 0.4em;*/
|
||||
}
|
||||
|
||||
.openerp .oe-dashboard .ui-sortable-placeholder {
|
||||
|
@ -126,3 +130,10 @@
|
|||
top: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.openerp .oe-dashboard-action .view-manager-main-content {
|
||||
padding: 2px;
|
||||
}
|
||||
.openerp .oe-dashboard-action-header .ui-icon, .openerp .oe-dashboard-action-header .oe-dashboard-action-rename {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,10 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
|
|||
});
|
||||
});
|
||||
|
||||
this.$element.find('a.oe-dashboard-action-rename').live('click', this.on_rename);
|
||||
//this.$element.find('a.oe-dashboard-action-rename').live('click', this.on_rename);
|
||||
this.$element.find('.oe-dashboard-action').live('mouseover mouseout', function(event) {
|
||||
$(this).find('.oe-dashboard-action-header .ui-icon, .oe-dashboard-action-header .oe-dashboard-action-rename').toggle(event.type == 'mouseover');
|
||||
});
|
||||
},
|
||||
on_undo: function() {
|
||||
this.rpc('/base/view/undo_custom', {
|
||||
|
@ -59,8 +62,6 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
|
|||
res_model : 'ir.actions.actions',
|
||||
views : [[false, 'list']],
|
||||
type : 'ir.actions.act_window',
|
||||
view_type : 'list',
|
||||
view_mode : 'list',
|
||||
limit : 80,
|
||||
auto_search : true,
|
||||
domain : [['type', '=', 'ir.actions.act_window']],
|
||||
|
@ -73,7 +74,6 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
|
|||
// TODO: create a Dialog controller which optionally takes an action
|
||||
// Should set width & height automatically and take buttons & views callback
|
||||
var dialog_id = _.uniqueId('act_window_dialog');
|
||||
var action_manager = new openerp.base.ActionManager(this.session, dialog_id);
|
||||
var $dialog = $('<div id=' + dialog_id + '>').dialog({
|
||||
modal : true,
|
||||
title : 'Actions',
|
||||
|
@ -89,8 +89,7 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
|
|||
}
|
||||
}
|
||||
});
|
||||
action_manager.start();
|
||||
action_manager.do_action(action);
|
||||
new openerp.base.ViewManagerAction(this, dialog_id, action).start();
|
||||
// TODO: should bind ListView#select_record in order to catch record clicking
|
||||
},
|
||||
do_add_widget : function(action_manager) {
|
||||
|
@ -227,10 +226,9 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
|
|||
views_switcher : false,
|
||||
action_buttons : false,
|
||||
pager: false
|
||||
}
|
||||
var element_id = this.view.element_id + '_action_' + action.id;
|
||||
var view = new openerp.base.ViewManagerAction(this.session, element_id, action);
|
||||
view.start();
|
||||
};
|
||||
new openerp.base.ViewManagerAction(this,
|
||||
this.view.element_id + '_action_' + action.id, action).start();
|
||||
},
|
||||
render: function() {
|
||||
// We should start with three columns available
|
||||
|
|
|
@ -29,15 +29,15 @@
|
|||
</table>
|
||||
</t>
|
||||
<t t-name="DashBoard.action">
|
||||
<div t-att-data-id="action.attrs.name" class="oe-dashboard-action ui-widget ui-widget-content ui-helper-clearfix ui-corner-all">
|
||||
<div class="oe-dashboard-action-header ui-widget-header ui-corner-all">
|
||||
<a href="#" class="oe-dashboard-action-rename"><img src="/base/static/src/img/icons/gtk-edit.png" width="16" height="16"/></a>
|
||||
<span class="oe-dashboard-action-title"><t t-esc="action.attrs.string"/></span>
|
||||
<div t-att-data-id="action.attrs.name" class="oe-dashboard-action">
|
||||
<h2 class="oe-dashboard-action-header oe_view_title">
|
||||
<t t-esc="action.attrs.string"/>
|
||||
<!--<a href="#" class="oe-dashboard-action-rename"><img src="/base/static/src/img/icons/gtk-edit.png" width="16" height="16"/></a>-->
|
||||
<input class="oe-dashboard-action-input" type="text" name="title" value="" style="display: none"/>
|
||||
<span class='ui-icon ui-icon-closethick'></span>
|
||||
<span class='ui-icon ui-icon-minusthick oe-dashboard-fold' t-if="!action.attrs.fold"></span>
|
||||
<span class='ui-icon ui-icon-plusthick oe-dashboard-fold' t-if="action.attrs.fold"></span>
|
||||
</div>
|
||||
</h2>
|
||||
<div t-att-id="view.element_id + '_action_' + action.attrs.name" class="oe-dashboard-action-content" t-att-style="action.attrs.fold ? 'display: none' : null"></div>
|
||||
</div>
|
||||
</t>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
openerp.base.diagram = function (openerp) {
|
||||
|
||||
openerp.base.views.add('diagram', 'openerp.base.DiagramView');
|
||||
openerp.base.DiagramView = openerp.base.Controller.extend({
|
||||
openerp.base.DiagramView = openerp.base.Widget.extend({
|
||||
init: function(view_manager, session, element_id, dataset, view_id){
|
||||
this._super(session, element_id);
|
||||
this.view_manager = view_manager;
|
||||
|
|
|
@ -1,33 +1,3 @@
|
|||
dhtmlx=function(obj){
|
||||
for (var a in obj) dhtmlx[a]=obj[a];
|
||||
return dhtmlx; //simple singleton
|
||||
};
|
||||
dhtmlx.extend_api=function(name,map,ext){
|
||||
var t = window[name];
|
||||
if (!t) return; //component not defined
|
||||
window[name]=function(obj){
|
||||
if (obj && typeof obj == "object" && !obj.tagName){
|
||||
var that = t.apply(this,(map._init?map._init(obj):arguments));
|
||||
//global settings
|
||||
for (var a in dhtmlx)
|
||||
if (map[a]) this[map[a]](dhtmlx[a]);
|
||||
//local settings
|
||||
for (var a in obj){
|
||||
if (map[a]) this[map[a]](obj[a]);
|
||||
else if (a.indexOf("on")==0){
|
||||
this.attachEvent(a,obj[a]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
var that = t.apply(this,arguments);
|
||||
if (map._patch) map._patch(this);
|
||||
return that||this;
|
||||
};
|
||||
window[name].prototype=t.prototype;
|
||||
if (ext)
|
||||
dhtmlXHeir(window[name].prototype,ext);
|
||||
};
|
||||
|
||||
dhtmlxAjax={
|
||||
get:function(url,callback){
|
||||
var t=new dtmlXMLLoaderObject(true);
|
||||
|
|
|
@ -2,37 +2,6 @@
|
|||
Copyright DHTMLX LTD. http://www.dhtmlx.com
|
||||
To use this component please contact sales@dhtmlx.com to obtain license
|
||||
*/
|
||||
|
||||
dhtmlx=function(obj){
|
||||
for (var a in obj) dhtmlx[a]=obj[a];
|
||||
return dhtmlx; //simple singleton
|
||||
};
|
||||
dhtmlx.extend_api=function(name,map,ext){
|
||||
var t = window[name];
|
||||
if (!t) return; //component not defined
|
||||
window[name]=function(obj){
|
||||
if (obj && typeof obj == "object" && !obj.tagName){
|
||||
var that = t.apply(this,(map._init?map._init(obj):arguments));
|
||||
//global settings
|
||||
for (var a in dhtmlx)
|
||||
if (map[a]) this[map[a]](dhtmlx[a]);
|
||||
//local settings
|
||||
for (var a in obj){
|
||||
if (map[a]) this[map[a]](obj[a]);
|
||||
else if (a.indexOf("on")==0){
|
||||
this.attachEvent(a,obj[a]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
var that = t.apply(this,arguments);
|
||||
if (map._patch) map._patch(this);
|
||||
return that||this;
|
||||
};
|
||||
window[name].prototype=t.prototype;
|
||||
if (ext)
|
||||
dhtmlXHeir(window[name].prototype,ext);
|
||||
};
|
||||
|
||||
dhtmlxAjax={
|
||||
get:function(url,callback){
|
||||
var t=new dtmlXMLLoaderObject(true);
|
||||
|
|
|
@ -1162,7 +1162,7 @@ GanttProject.prototype.deleteChildTask = function(task)
|
|||
* @type: public
|
||||
* @topic: 1
|
||||
*/
|
||||
GanttProject.prototype.insertTask = function(id, name, EST, Duration, PercentCompleted, predecessorTaskId, parentTaskId)
|
||||
GanttProject.prototype.insertTask = function(id, name, EST, Duration, PercentCompleted, predecessorTaskId, color, parentTaskId)
|
||||
{
|
||||
var task = null;
|
||||
var _task = null;
|
||||
|
@ -1205,7 +1205,7 @@ GanttProject.prototype.insertTask = function(id, name, EST, Duration, PercentCom
|
|||
return false;
|
||||
}
|
||||
|
||||
task = new GanttTaskInfo(id, name, EST, Duration, PercentCompleted, predecessorTaskId);
|
||||
task = new GanttTaskInfo(id, name, EST, Duration, PercentCompleted, predecessorTaskId, color);
|
||||
|
||||
if (!this.Chart.checkPosParentTask(parentTask, task)) {
|
||||
this.Chart.Error.throwError("DATA_INSERT_ERROR", 19, [parentTaskId,id]);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
openerp.base_gantt = function (openerp) {
|
||||
QWeb.add_template('/base_gantt/static/src/xml/base_gantt.xml');
|
||||
openerp.base.views.add('gantt', 'openerp.base_gantt.GanttView');
|
||||
openerp.base_gantt.GanttView = openerp.base.Controller.extend({
|
||||
openerp.base_gantt.GanttView = openerp.base.Widget.extend({
|
||||
|
||||
init: function(view_manager, session, element_id, dataset, view_id) {
|
||||
|
||||
|
@ -24,7 +24,6 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
this.date_delay = "";
|
||||
this.date_stop = "";
|
||||
this.color_field = "";
|
||||
this.day_lenth = 8;
|
||||
this.colors = [];
|
||||
this.color_values = [];
|
||||
this.calendar_fields = {};
|
||||
|
@ -58,6 +57,7 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
this.parent = this.fields_view.arch.children[0].attrs.link;
|
||||
|
||||
this.format = "yyyy-MM-dd";
|
||||
this.grp = [];
|
||||
|
||||
self.create_gantt();
|
||||
self.get_events();
|
||||
|
@ -81,7 +81,7 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
get_events: function() {
|
||||
|
||||
var self = this;
|
||||
this.dataset.read_ids(this.dataset.ids, {}, function(result) {
|
||||
this.dataset.read_slice(false, false, false, function(result) {
|
||||
self.load_event(result);
|
||||
});
|
||||
|
||||
|
@ -91,7 +91,6 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
|
||||
var self = this;
|
||||
var result = events;
|
||||
var project = {};
|
||||
var smalldate = "";
|
||||
|
||||
COLOR_PALETTE = ['#ccccff', '#cc99ff', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
|
||||
|
@ -118,13 +117,21 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
}
|
||||
}
|
||||
}
|
||||
project = new GanttProjectInfo(1, self.name, smalldate);
|
||||
ganttChartControl.addProject(project);
|
||||
if (smalldate == ""){
|
||||
smalldate = Date.today();
|
||||
}
|
||||
project = new GanttProjectInfo("_1", "", smalldate);
|
||||
ganttChartControl.addProject(project);
|
||||
}
|
||||
|
||||
//create child
|
||||
var k = 0;
|
||||
var color_box = {};
|
||||
var parents = {};
|
||||
var all_events = {};
|
||||
var child_event = {};
|
||||
var temp_id = "";
|
||||
var final_events = [];
|
||||
for (i in show_event) {
|
||||
|
||||
var res = show_event[i];
|
||||
|
@ -153,8 +160,129 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
}
|
||||
if (duration == false)
|
||||
duration = 0
|
||||
task = new GanttTaskInfo(id, text, start_date, duration, 100, "", color_box[color]);
|
||||
project.addTask(task);
|
||||
|
||||
if (self.grp.length == 0){
|
||||
self.grp.push({'group_by' : this.parent})
|
||||
}
|
||||
if (self.grp != undefined){
|
||||
for (j in self.grp){
|
||||
var grp_key = res[self.grp[j]['group_by']];
|
||||
if (typeof(grp_key) == "object"){
|
||||
grp_key = res[self.grp[j]['group_by']][1];
|
||||
}
|
||||
else{
|
||||
grp_key = res[self.grp[j]['group_by']];
|
||||
}
|
||||
|
||||
if (grp_key == false){
|
||||
grp_key = "False";
|
||||
}
|
||||
|
||||
if (j == 0){
|
||||
if (parents[grp_key] == undefined){
|
||||
var mod_id = i+ "_" +j;
|
||||
parents[grp_key] = mod_id;
|
||||
child_event[mod_id] = {};
|
||||
all_events[mod_id] = {'parent': "", 'evt':[mod_id , grp_key, start_date, start_date, 100, "", "white"]};
|
||||
}
|
||||
else{
|
||||
mod_id = parents[grp_key];
|
||||
}
|
||||
temp_id = mod_id;
|
||||
}else{
|
||||
if (child_event[mod_id][grp_key] == undefined){
|
||||
var ch_mod_id = i+ "_" +j;
|
||||
child_event[mod_id][grp_key] = ch_mod_id;
|
||||
child_event[ch_mod_id] = {};
|
||||
temp_id = ch_mod_id;
|
||||
all_events[ch_mod_id] = {'parent': mod_id, 'evt':[ch_mod_id , grp_key, start_date, start_date, 100, "","white"]};
|
||||
mod_id = ch_mod_id;
|
||||
}
|
||||
else{
|
||||
mod_id = child_event[mod_id][grp_key];
|
||||
temp_id = mod_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
all_events[id] = {'parent': temp_id, 'evt':[id , text, start_date, duration, 100, "", color_box[color]]};
|
||||
final_events.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
for (i in final_events){
|
||||
var evt_id = final_events[i];
|
||||
var evt_date = all_events[evt_id]['evt'][2];
|
||||
while (all_events[evt_id]['parent'] != "") {
|
||||
var parent_id =all_events[evt_id]['parent'];
|
||||
if (all_events[parent_id]['evt'][2] > evt_date){
|
||||
all_events[parent_id]['evt'][2] = evt_date;
|
||||
}
|
||||
evt_id = parent_id;
|
||||
}
|
||||
}
|
||||
var evt_id = [];
|
||||
var evt_date = "";
|
||||
var evt_duration = "";
|
||||
var evt_end_date = "";
|
||||
|
||||
for (i in final_events){
|
||||
evt_id = final_events[i];
|
||||
evt_date = all_events[evt_id]['evt'][2];
|
||||
evt_duration = all_events[evt_id]['evt'][3];
|
||||
|
||||
evt_str_date = this.convert_date_str(evt_date);
|
||||
evt_end_date = this.end_date(evt_str_date, evt_duration);
|
||||
|
||||
while (all_events[evt_id]['parent'] != "") {
|
||||
var parent_id =all_events[evt_id]['parent'];
|
||||
if (all_events[parent_id]['evt'][3] < evt_end_date){
|
||||
all_events[parent_id]['evt'][3] = evt_end_date;
|
||||
}
|
||||
evt_id = parent_id;
|
||||
}
|
||||
}
|
||||
|
||||
for (j in self.grp){
|
||||
for (i in all_events){
|
||||
res = all_events[i];
|
||||
if ((typeof(res['evt'][3])) == "object"){
|
||||
res['evt'][3] = self.hours_between(res['evt'][2],res['evt'][3]);
|
||||
}
|
||||
|
||||
k = res['evt'][0].toString().indexOf('_');
|
||||
if (k != -1){
|
||||
if (res['evt'][0].substring(k) == "_"+j){
|
||||
if (j == 0){
|
||||
task = new GanttTaskInfo(res['evt'][0], res['evt'][1], res['evt'][2], res['evt'][3], res['evt'][4], "",res['evt'][6]);
|
||||
project.addTask(task);
|
||||
} else {
|
||||
task = new GanttTaskInfo(res['evt'][0], res['evt'][1], res['evt'][2], res['evt'][3], res['evt'][4], "",res['evt'][6]);
|
||||
prt = project.getTaskById(res['parent']);
|
||||
prt.addChildTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i in final_events){
|
||||
evt_id = final_events[i];
|
||||
res = all_events[evt_id];
|
||||
|
||||
task=new GanttTaskInfo(res['evt'][0], res['evt'][1], res['evt'][2], res['evt'][3], res['evt'][4], "",res['evt'][6]);
|
||||
prt = project.getTaskById(res['parent']);
|
||||
prt.addChildTask(task);
|
||||
}
|
||||
|
||||
oth_hgt = 264;
|
||||
min_hgt = 150;
|
||||
name_min_wdt = 150;
|
||||
gantt_hgt = jQuery(window).height() - oth_hgt;
|
||||
search_wdt = jQuery("#oe_app_search").width();
|
||||
|
||||
if (gantt_hgt > min_hgt){
|
||||
jQuery('#GanttDiv').height(gantt_hgt).width(search_wdt);
|
||||
} else{
|
||||
jQuery('#GanttDiv').height(min_hgt).width(search_wdt);
|
||||
}
|
||||
|
||||
ganttChartControl.create("GanttDiv");
|
||||
|
@ -163,6 +291,69 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_resize_drag_end(task, "drag");});
|
||||
ganttChartControl.attachEvent("onTaskDblClick", function(task) {self.open_popup(task);});
|
||||
|
||||
taskdiv = jQuery("div.taskPanel").parent();
|
||||
taskdiv.addClass('ganttTaskPanel');
|
||||
taskdiv.prev().addClass('ganttDayPanel');
|
||||
$gantt_panel = jQuery(".ganttTaskPanel , .ganttDayPanel");
|
||||
|
||||
ganttrow = jQuery('.taskPanel').closest('tr');
|
||||
gtd = ganttrow.children(':first-child');
|
||||
gtd.children().addClass('task-name');
|
||||
|
||||
jQuery(".toggle-sidebar").click(function(e) {
|
||||
self.set_width();
|
||||
});
|
||||
|
||||
jQuery(window).bind('resize',function(){
|
||||
window.clearTimeout(ganttChartControl._resize_timer);
|
||||
ganttChartControl._resize_timer = window.setTimeout(function(){
|
||||
self.reload_gantt();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
jQuery("div #_1, div #_1 + div").hide();
|
||||
},
|
||||
|
||||
set_width: function() {
|
||||
|
||||
$gantt_panel.width(1);
|
||||
jQuery(".ganttTaskPanel").parent().width(1);
|
||||
|
||||
search_wdt = jQuery("#oe_app_search").width();
|
||||
day_wdt = jQuery(".ganttDayPanel").children().children().width();
|
||||
name_wdt = jQuery('.task-name').width();
|
||||
jQuery('#GanttDiv').css('width','100%');
|
||||
|
||||
if (search_wdt - day_wdt <= name_min_wdt){
|
||||
jQuery(".ganttTaskPanel").parent().width(search_wdt - name_min_wdt);
|
||||
jQuery(".ganttTaskPanel").width(search_wdt - name_min_wdt);
|
||||
jQuery(".ganttDayPanel").width(search_wdt - name_min_wdt - 14);
|
||||
jQuery('.task-name').width(name_min_wdt);
|
||||
jQuery('.task-name').children().width(name_min_wdt);
|
||||
}else{
|
||||
jQuery(".ganttTaskPanel").parent().width(day_wdt);
|
||||
jQuery(".ganttTaskPanel").width(day_wdt);
|
||||
jQuery(".taskPanel").width(day_wdt - 16);
|
||||
jQuery(".ganttDayPanel").width(day_wdt -16);
|
||||
jQuery('.task-name').width(search_wdt - day_wdt);
|
||||
jQuery('.task-name').children().width(search_wdt - day_wdt);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
end_date: function(dat, duration) {
|
||||
|
||||
var self = this;
|
||||
|
||||
dat = this.convert_str_date(dat);
|
||||
|
||||
var day = Math.floor(duration/self.day_length);
|
||||
var hrs = duration % self.day_length;
|
||||
|
||||
dat.add(day).days();
|
||||
dat.add(hrs).hour();
|
||||
|
||||
return dat;
|
||||
},
|
||||
|
||||
hours_between: function(date1, date2) {
|
||||
|
@ -172,15 +363,18 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
var date2_ms = date2.getTime();
|
||||
var difference_ms = Math.abs(date1_ms - date2_ms);
|
||||
|
||||
d = Math.round(difference_ms / ONE_DAY);
|
||||
h = Math.round((difference_ms % ONE_DAY)/(1000 * 60 * 60));
|
||||
|
||||
return (d * this.day_length) + h;
|
||||
d = Math.floor(difference_ms / ONE_DAY);
|
||||
h = (difference_ms % ONE_DAY)/(1000 * 60 * 60);
|
||||
num = (d * this.day_length) + h;
|
||||
return parseFloat(num.toFixed(2));
|
||||
|
||||
},
|
||||
|
||||
open_popup : function(task) {
|
||||
var event_id = task.getId();
|
||||
|
||||
if(event_id.toString().search("_") != -1)
|
||||
return;
|
||||
if (event_id) {
|
||||
event_id = parseInt(event_id, 10);
|
||||
var dataset_event_index = jQuery.inArray(event_id, this.ids);
|
||||
|
@ -214,6 +408,8 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
var event_id = task.getId();
|
||||
var data = {};
|
||||
|
||||
if(event_id.toString().search("_") != -1)
|
||||
return;
|
||||
if (evt == "drag"){
|
||||
full_date = task.getEST().set({hour: self.hh, minute : self.mm, second:0});
|
||||
data[this.date_start] = this.convert_date_str(full_date);
|
||||
|
@ -262,27 +458,18 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
throw "Unrecognized date/time format";
|
||||
},
|
||||
|
||||
reload_gantt: function(domain) {
|
||||
reload_gantt: function() {
|
||||
var self = this;
|
||||
var ajax = {
|
||||
url: '/base/dataset/search_read',
|
||||
async: false
|
||||
};
|
||||
this.rpc(ajax, {
|
||||
model: this.dataset.model,
|
||||
domain: self.dataset.domain,
|
||||
context :self.dataset.context
|
||||
}, function(response) {
|
||||
ganttChartControl.clearAll();
|
||||
jQuery("#GanttDiv").children().remove();
|
||||
self.load_event(response);
|
||||
});
|
||||
this.dataset.read_slice(false, false, false, function(response) {
|
||||
ganttChartControl.clearAll();
|
||||
jQuery("#GanttDiv").children().remove();
|
||||
self.load_event(response);
|
||||
});
|
||||
},
|
||||
|
||||
do_search: function (domains, contexts, groupbys) {
|
||||
|
||||
var self = this;
|
||||
|
||||
this.grp = groupbys;
|
||||
return this.rpc('/base/session/eval_domain_and_context', {
|
||||
domains: domains,
|
||||
contexts: contexts,
|
||||
|
@ -290,7 +477,7 @@ init: function(view_manager, session, element_id, dataset, view_id) {
|
|||
}, function (results) {
|
||||
self.dataset.context = results.context;
|
||||
self.dataset.domain = results.domain;
|
||||
return self.reload_gantt(self.dataset.domain);
|
||||
self.reload_gantt();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
<template>
|
||||
<t t-name="GanttView">
|
||||
<h3 class="title"><t t-esc="view.fields_view.arch.attrs.string"/></h3>
|
||||
<table class="gantt-view" width="100%" height="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div style="width:100%;height:300px;position:relative" id="GanttDiv"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="padding-top:6px;position:relative" id="GanttDiv"/>
|
||||
</t>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/python
|
||||
import controllers
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "Base Graph",
|
||||
"version": "2.0",
|
||||
"depends": ['base'],
|
||||
"js": [
|
||||
"static/lib/dhtmlxGraph/codebase/dhtmlxchart.js",
|
||||
"static/src/js/graph.js"],
|
||||
"css": ["static/lib/dhtmlxGraph/codebase/dhtmlxchart.css"],
|
||||
"active": True
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
import main
|
|
@ -0,0 +1,11 @@
|
|||
from base.controllers.main import View
|
||||
import openerpweb
|
||||
|
||||
class GraphView(View):
|
||||
_cp_path = "/base_graph/graphview"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req, model, view_id):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'graph')
|
||||
all_fields = req.session.model(model).fields_get()
|
||||
return {'fields_view': fields_view, 'all_fields':all_fields}
|
|
@ -0,0 +1,73 @@
|
|||
<h1>GNU GENERAL PUBLIC LICENSE</h1>
|
||||
Version 2, June 1991 </p>
|
||||
</p>
|
||||
<p>Copyright (C) 1989, 1991 Free Software Foundation, Inc. </p>
|
||||
<p>59 Temple Place - Suite 330, Boston, MA 02111-1307, USA</p>
|
||||
</p>
|
||||
<p>Everyone is permitted to copy and distribute verbatim copies</p>
|
||||
<p>of this license document, but changing it is not allowed.</p>
|
||||
</p>
|
||||
</p>
|
||||
<p>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</p>
|
||||
<p>0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". </p>
|
||||
</p>
|
||||
<p>Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. </p>
|
||||
</p>
|
||||
<p>1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. </p>
|
||||
</p>
|
||||
<p>You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. </p>
|
||||
</p>
|
||||
<p>2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: </p>
|
||||
</p>
|
||||
</p>
|
||||
<p>a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. </p>
|
||||
</p>
|
||||
<p>b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. </p>
|
||||
</p>
|
||||
<p>c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) </p>
|
||||
<p>These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. </p>
|
||||
</p>
|
||||
<p>Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. </p>
|
||||
</p>
|
||||
<p>In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. </p>
|
||||
</p>
|
||||
<p>3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: </p>
|
||||
</p>
|
||||
<p>a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </p>
|
||||
</p>
|
||||
<p>b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </p>
|
||||
</p>
|
||||
<p>c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) </p>
|
||||
<p>The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. </p>
|
||||
</p>
|
||||
<p>If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. </p>
|
||||
</p>
|
||||
<p>4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. </p>
|
||||
</p>
|
||||
<p>5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. </p>
|
||||
</p>
|
||||
<p>6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. </p>
|
||||
</p>
|
||||
<p>7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. </p>
|
||||
</p>
|
||||
<p>If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. </p>
|
||||
</p>
|
||||
<p>It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. </p>
|
||||
</p>
|
||||
<p>This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. </p>
|
||||
</p>
|
||||
<p>8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. </p>
|
||||
</p>
|
||||
<p>9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. </p>
|
||||
</p>
|
||||
<p>Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. </p>
|
||||
</p>
|
||||
<p>10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. </p>
|
||||
</p>
|
||||
<p>NO WARRANTY</p>
|
||||
</p>
|
||||
<p>11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. </p>
|
||||
</p>
|
||||
<p>12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. </p>
|
||||
</p>
|
||||
<p>
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
Copyright DHTMLX LTD. http://www.dhtmlx.com
|
||||
You allowed to use this component or parts of it under GPL terms
|
||||
To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
|
||||
*/
|
||||
.dhx_tooltip{display:none;position:absolute;font-family:Tahoma;font-size:8pt;z-index:10000;background-color:white;padding:2px 2px 2px 2px;border:1px solid #A4BED4;}
|
||||
.dhx_chart{position:relative;font-family:Verdana;font-size:13px;color:#000;overflow:hidden;}
|
||||
.dhx_canvas_text{position:absolute;text-align:center;}
|
||||
.dhx_map_img{width:100%;height:100%;position:absolute;top:0;left:0;border:0;filter:alpha(opacity=0);}
|
||||
.dhx_axis_item_y{position:absolute;height:10px;line-height:10px;text-align:right;}
|
||||
.dhx_axis_title_y{text-align:center;font-family:Verdana;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-o-transform:rotate(-90deg);padding-left:3px;}
|
||||
.dhx_axis_item_x{text-align:right;margin-top:30px;margin-left:-14px;font-size:8pt;-webkit-transform:rotate(-60deg);-moz-transform:rotate(-60deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-o-transform:rotate(-60deg);padding-left:3px;}
|
||||
.dhx_axis_title_x{text-align:center;margin-top:50px;}
|
||||
.dhx_chart_legend{position:absolute;}
|
||||
.dhx_chart_legend_item{height:18px;line-height:18px;padding:2px;}
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
Copyright DHTMLX LTD. http://www.dhtmlx.com
|
||||
You allowed to use this component or parts of it under GPL terms
|
||||
To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
|
||||
*/
|
||||
window.dhtmlx||(dhtmlx={});dhtmlx.version="3.0";dhtmlx.codebase="./";dhtmlx.extend=function(a,b){for(var c in b)a[c]=b[c];b.k&&a.k();return a};
|
||||
dhtmlx.proto_extend=function(){for(var a=arguments,b=a[0],c=[],d=a.length-1;d>0;d--){if(typeof a[d]=="function")a[d]=a[d].prototype;for(var e in a[d])if(e=="_init")c.push(a[d][e]);else b[e]||(b[e]=a[d][e])}a[0].k&&c.push(a[0].k);b.k=function(){for(var g=0;g<c.length;g++)c[g].apply(this,arguments)};b.base=a[1];var f=function(g){this.k(g);this.B&&this.B(g,this.defaults)};f.prototype=b;b=a=null;return f};dhtmlx.bind=function(a,b){return function(){return a.apply(b,arguments)}};
|
||||
dhtmlx.require=function(a){if(!dhtmlx.ha[a]){dhtmlx.exec(dhtmlx.ajax().sync().get(dhtmlx.codebase+a).responseText);dhtmlx.ha[a]=true}};dhtmlx.ha={};dhtmlx.exec=function(a){window.execScript?window.execScript(a):window.eval(a)};dhtmlx.methodPush=function(a,b){return function(){var c=false;return c=a[b].apply(a,arguments)}};dhtmlx.isNotDefined=function(a){return typeof a=="undefined"};dhtmlx.delay=function(a,b,c,d){setTimeout(function(){var e=a.apply(b,c);a=b=c=null;return e},d||1)};
|
||||
dhtmlx.uid=function(){if(!this.S)this.S=(new Date).valueOf();this.S++;return this.S};dhtmlx.toNode=function(a){if(typeof a=="string")return document.getElementById(a);return a};dhtmlx.toArray=function(a){return dhtmlx.extend(a||[],dhtmlx.PowerArray)};dhtmlx.toFunctor=function(a){return typeof a=="string"?eval(a):a};dhtmlx.j={};
|
||||
dhtmlx.event=function(a,b,c,d){a=dhtmlx.toNode(a);var e=dhtmlx.uid();dhtmlx.j[e]=[a,b,c];if(d)c=dhtmlx.bind(c,d);if(a.addEventListener)a.addEventListener(b,c,false);else a.attachEvent&&a.attachEvent("on"+b,c);return e};dhtmlx.eventRemove=function(a){if(a){var b=dhtmlx.j[a];if(b[0].removeEventListener)b[0].removeEventListener(b[1],b[2],false);else b[0].detachEvent&&b[0].detachEvent("on"+b[1],b[2]);delete this.j[a]}};
|
||||
dhtmlx.EventSystem={k:function(){this.j={};this.A={};this.s={}},block:function(){this.j.U=true},unblock:function(){this.j.U=false},mapEvent:function(a){dhtmlx.extend(this.s,a)},callEvent:function(a,b){if(this.j.U)return true;a=a.toLowerCase();var c=this.j[a.toLowerCase()],d=true;if(c)for(var e=0;e<c.length;e++)if(c[e].apply(this,b||[])===false)d=false;if(this.s[a]&&!this.s[a].callEvent(a,b))d=false;return d},attachEvent:function(a,b,c){a=a.toLowerCase();c=c||dhtmlx.uid();b=dhtmlx.toFunctor(b);var d=
|
||||
this.j[a]||dhtmlx.toArray();d.push(b);this.j[a]=d;this.A[c]={f:b,t:a};return c},detachEvent:function(a){var b=this.A[a].t,c=this.A[a].f;b=this.j[b];b.remove(c);delete this.A[a]}};
|
||||
dhtmlx.PowerArray={removeAt:function(a,b){if(a>=0)this.splice(a,b||1)},remove:function(a){this.removeAt(this.find(a))},insertAt:function(a,b){if(!b&&b!==0)this.push(a);else{var c=this.splice(b,this.length-b);this[b]=a;this.push.apply(this,c)}},find:function(a){for(i=0;i<this.length;i++)if(a==this[i])return i;return-1},each:function(a,b){for(var c=0;c<this.length;c++)a.call(b||this,this[c])},map:function(a,b){for(var c=0;c<this.length;c++)this[c]=a.call(b||this,this[c]);return this}};dhtmlx.env={};
|
||||
if(navigator.userAgent.indexOf("Opera")!=-1)dhtmlx.La=true;else{dhtmlx.r=!!document.all;dhtmlx.Ka=!document.all;dhtmlx.Ma=navigator.userAgent.indexOf("KHTML")!=-1;if(navigator.appVersion.indexOf("MSIE 8.0")!=-1&&document.compatMode!="BackCompat")dhtmlx.r=8}dhtmlx.env={};
|
||||
(function(){dhtmlx.env.transform=false;dhtmlx.env.transition=false;var a={};a.names=["transform","transition"];a.transform=["transform","WebkitTransform","MozTransform","oTransform"];a.transition=["transition","WebkitTransition","MozTransition","oTransition"];for(var b=document.createElement("DIV"),c=0;c<a.names.length;c++)for(;p=a[a.names[c]].pop();)if(typeof b.style[p]!="undefined")dhtmlx.env[a.names[c]]=true})();
|
||||
dhtmlx.env.transform_prefix=function(){var a;if(dhtmlx.La)a="-o-";else{a="";if(dhtmlx.Ka)a="-moz-";if(dhtmlx.Ma)a="-webkit-"}return a}();dhtmlx.env.svg=function(){return document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")}();dhtmlx.zIndex={drag:1E4};
|
||||
dhtmlx.html={create:function(a,b,c){b=b||{};var d=document.createElement(a);for(var e in b)d.setAttribute(e,b[e]);if(b.style)d.style.cssText=b.style;if(b["class"])d.className=b["class"];if(c)d.innerHTML=c;return d},getValue:function(a){a=dhtmlx.toNode(a);if(!a)return"";return dhtmlx.isNotDefined(a.value)?a.innerHTML:a.value},remove:function(a){if(a instanceof Array)for(var b=0;b<a.length;b++)this.remove(a[b]);else a&&a.parentNode&&a.parentNode.removeChild(a)},insertBefore:function(a,b,c){if(a)b?b.parentNode.insertBefore(a,
|
||||
b):c.appendChild(a)},locate:function(a,b){a=a||event;for(var c=a.target||a.srcElement;c;){if(c.getAttribute){var d=c.getAttribute(b);if(d)return d}c=c.parentNode}return null},offset:function(a){if(a.getBoundingClientRect){var b=a.getBoundingClientRect(),c=document.body,d=document.documentElement,e=window.pageYOffset||d.scrollTop||c.scrollTop,f=window.pageXOffset||d.scrollLeft||c.scrollLeft,g=d.clientTop||c.clientTop||0,i=d.clientLeft||c.clientLeft||0,j=b.top+e-g,k=b.left+f-i;return{y:Math.round(j),
|
||||
x:Math.round(k)}}else{for(k=j=0;a;){j+=parseInt(a.offsetTop,10);k+=parseInt(a.offsetLeft,10);a=a.offsetParent}return{y:j,x:k}}},pos:function(a){a=a||event;if(a.pageX||a.pageY)return{x:a.pageX,y:a.pageY};var b=dhtmlx.r&&document.compatMode!="BackCompat"?document.documentElement:document.body;return{x:a.clientX+b.scrollLeft-b.clientLeft,y:a.clientY+b.scrollTop-b.clientTop}},preventEvent:function(a){a&&a.preventDefault&&a.preventDefault();dhtmlx.html.stopEvent(a)},stopEvent:function(a){(a||event).cancelBubble=
|
||||
true;return false},addCss:function(a,b){a.className+=" "+b},removeCss:function(a,b){a.className=a.className.replace(RegExp(b,"g"),"")}};(function(){var a=document.getElementsByTagName("SCRIPT");if(a.length){a=(a[a.length-1].getAttribute("src")||"").split("/");a.splice(a.length-1,1);dhtmlx.codebase=a.slice(0,a.length).join("/")+"/"}})();dhtmlx.ui={};
|
||||
dhtmlx.Destruction={k:function(){dhtmlx.destructors.push(this)},destructor:function(){this.destructor=function(){};this.ib=this.v=null;this.fa&&document.body.appendChild(this.fa);this.fa=null;if(this.g){this.g.innerHTML="";this.g.v=null}this.data=this.g=this.L=null;this.j=this.A={}}};dhtmlx.destructors=[];
|
||||
dhtmlx.event(window,"unload",function(){for(var a=0;a<dhtmlx.destructors.length;a++)dhtmlx.destructors[a].destructor();dhtmlx.destructors=[];for(var b in dhtmlx.j){a=dhtmlx.j[b];if(a[0].removeEventListener)a[0].removeEventListener(a[1],a[2],false);else a[0].detachEvent&&a[0].detachEvent("on"+a[1],a[2]);delete dhtmlx.j[b]}});dhtmlx.math={};dhtmlx.math.fb=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
|
||||
dhtmlx.math.toHex=function(a,b){a=parseInt(a,10);for(str="";a>0;){str=this.fb[a%16]+str;a=Math.floor(a/16)}for(;str.length<b;)str="0"+str;return str};dhtmlx.ui.Map=function(a){this.name="Map";this.q="map_"+dhtmlx.uid();this.Pa=a;this.s=[]};
|
||||
dhtmlx.ui.Map.prototype={addRect:function(a,b,c){this.X(a,"RECT",b,c)},addPoly:function(a,b){this.X(a,"POLY",b)},X:function(a,b,c,d){var e="";if(arguments.length==4)e="userdata='"+d+"'";this.s.push("<area "+this.Pa+"='"+a+"' shape='"+b+"' coords='"+c.join()+"' "+e+"></area>")},addSector:function(a,b,c,d,e,f,g){var i=[];i.push(d);i.push(Math.floor(e*g));for(var j=b;j<c;j+=Math.PI/18){i.push(Math.floor(d+f*Math.cos(j)));i.push(Math.floor((e+f*Math.sin(j))*g))}i.push(Math.floor(d+f*Math.cos(c)));i.push(Math.floor((e+
|
||||
f*Math.sin(c))*g));i.push(d);i.push(Math.floor(e*g));return this.addPoly(a,i)},render:function(a){var b=dhtmlx.html.create("DIV");b.style.cssText="position:absolute; width:100%; height:100%; top:0px; left:0px;";a.appendChild(b);var c=dhtmlx.r?"":"src='data:image/gif;base64,R0lGODlhEgASAIAAAP///////yH5BAUUAAEALAAAAAASABIAAAIPjI+py+0Po5y02ouz3pwXADs='";b.innerHTML="<map id='"+this.q+"' name='"+this.q+"'>"+this.s.join("\n")+"</map><img "+c+" class='dhx_map_img' usemap='#"+this.q+"'>";a.v=b;this.s=[]}};
|
||||
dhtmlx.chart={};
|
||||
dhtmlx.chart.area={pvt_render_area:function(a,b,c,d,e,f){var g=this.C(a,b,c,d,e),i=Math.floor(g.cellWidth/2);if(b.length){a.globalAlpha=this.e.alpha.call(this,b[0]);a.fillStyle=this.e.color.call(this,b[0]);var j=this.p(b[0],c,d,g),k=this.e.offset?c.x+g.cellWidth*0.5:c.x;a.beginPath();a.moveTo(k,d.y);a.lineTo(k,j);f.addRect(b[0].id,[k-i,j-i,k+i,j+i]);this.e.yAxis||this.renderTextAt(false,!this.e.offset?false:true,k,j-this.e.labelOffset,this.e.label(b[0]));for(var h=1;h<b.length;h++){var m=k+Math.floor(g.cellWidth*
|
||||
h)-0.5,l=this.p(b[h],c,d,g);a.lineTo(m,l);f.addRect(b[h].id,[m-i,l-i,m+i,l+i]);this.e.yAxis||this.renderTextAt(false,!this.e.offset&&h==b.length-1?"left":"center",m,l-this.e.labelOffset,this.e.label(b[h]))}a.lineTo(k+Math.floor(g.cellWidth*[b.length-1]),d.y);a.lineTo(k,d.y);a.fill()}}};
|
||||
dhtmlx.chart.stackedArea={pvt_render_stackedArea:function(a,b,c,d,e,f){var g=this.C(a,b,c,d,e),i=Math.floor(g.cellWidth/2),j=[];if(b.length){a.globalAlpha=this.e.alpha.call(this,b[0]);a.fillStyle=this.e.color.call(this,b[0]);var k=e?b[0].$startY:d.y,h=this.e.offset?c.x+g.cellWidth*0.5:c.x,m=this.p(b[0],c,d,g)-(e?d.y-k:0);j[0]=m;a.beginPath();a.moveTo(h,k);a.lineTo(h,m);f.addRect(b[0].id,[h-i,m-i,h+i,m+i]);this.e.yAxis||this.renderTextAt(false,true,h,m-this.e.labelOffset,this.e.label(b[0]));for(var l=
|
||||
1;l<b.length;l++){var n=h+Math.floor(g.cellWidth*l)-0.5,o=this.p(b[l],c,d,g)-(e?d.y-b[l].$startY:0);j[l]=o;a.lineTo(n,o);f.addRect(b[l].id,[n-i,o-i,n+i,o+i]);this.e.yAxis||this.renderTextAt(false,true,n,o-this.e.labelOffset,this.e.label(b[l]))}a.lineTo(h+Math.floor(g.cellWidth*[b.length-1]),k);if(e)for(l=b.length-1;l>=0;l--){n=h+Math.floor(g.cellWidth*l)-0.5;var s=b[l].$startY;a.lineTo(n,s)}else a.lineTo(h+Math.floor(g.cellWidth*(length-1))-0.5,k);a.lineTo(h,k);a.fill();for(l=0;l<b.length;l++)b[l].$startY=
|
||||
j[l]}}};
|
||||
dhtmlx.chart.spline={pvt_render_spline:function(a,b,c,d,e){var f=this.C(a,b,c,d,e);Math.floor(f.cellWidth/2);var g=[];if(b.length){var i=this.e.offset?c.x+f.cellWidth*0.5:c.x;for(e=0;e<b.length;e++){var j=!e?i:Math.floor(f.cellWidth*e)-0.5+i,k=this.p(b[e],c,d,f);g.push({x:j,y:k})}var h=this.Ha(g);for(e=0;e<g.length-1;e++){var m=g[e].x;c=g[e].y;for(var l=g[e+1].x,n=g[e+1].y,o=m;o<l;o++)this.i(a,o,this.P(o,m,e,h.a,h.b,h.c,h.d),o+1,this.P(o+1,m,e,h.a,h.b,h.c,h.d),this.e.line.color(b[e]),this.e.line.width);this.i(a,
|
||||
l-1,this.P(o,m,e,h.a,h.b,h.c,h.d),l,n,this.e.line.color(b[e]),this.e.line.width);this.M(a,m,c,b[e],this.e.label(b[e]))}this.M(a,l,n,b[e],this.e.label(b[e]))}},Ha:function(a){var b,c,d,e,f,g,i,j,k;b=[];m=[];k=a.length;for(var h=0;h<k-1;h++){b[h]=a[h+1].x-a[h].x;m[h]=(a[h+1].y-a[h].y)/b[h]}c=[];d=[];c[0]=0;c[1]=2*(b[0]+b[1]);d[0]=0;d[1]=6*(m[1]-m[0]);for(h=2;h<k-1;h++){c[h]=2*(b[h-1]+b[h])-b[h-1]*b[h-1]/c[h-1];d[h]=6*(m[h]-m[h-1])-b[h-1]*d[h-1]/c[h-1]}e=[];e[k-1]=e[0]=0;for(h=k-2;h>=1;h--)e[h]=(d[h]-
|
||||
b[h]*e[h+1])/c[h];f=[];g=[];i=[];j=[];for(h=0;h<k-1;h++){f[h]=a[h].y;g[h]=-b[h]*e[h+1]/6-b[h]*e[h]/3+(a[h+1].y-a[h].y)/b[h];i[h]=e[h]/2;j[h]=(e[h+1]-e[h])/(6*b[h])}return{a:f,b:g,c:i,d:j}},P:function(a,b,c,d,e,f,g){return d[c]+(a-b)*(e[c]+(a-b)*(f[c]+(a-b)*g[c]))}};
|
||||
dhtmlx.chart.barH={pvt_render_barH:function(a,b,c,d,e,f){var g,i,j,k,h=d.x-c.x,m=!!this.e.yAxis,l=this.O("h");g=l.max;i=l.min;var n=Math.floor((d.y-c.y)/b.length);e||this.$(a,b,c,d,i,g,n);if(m){g=parseFloat(this.e.xAxis.end);i=parseFloat(this.e.xAxis.start)}var o=this.z(i,g);k=o[0];j=o[1];var s=k?h/k:10;if(!m){var t=10;s=k?(h-t)/k:10}var q=parseInt(this.e.width,10);if(q*this.h.length+4>n)q=n/this.h.length-4;var v=Math.floor((n-q*this.h.length)/2),p=typeof this.e.radius!="undefined"?parseInt(this.e.radius,
|
||||
10):Math.round(q/5),u=false,r=this.e.gradient;if(r&&typeof r!="function"){u=r;r=false}else if(r){r=a.createLinearGradient(c.x,c.y,d.x,c.y);this.e.gradient(r)}m||this.i(a,c.x-0.5,c.y,c.x-0.5,d.y,"#000000",1);for(d=0;d<b.length;d++){var w=parseFloat(this.e.value(b[d]));if(w>g)w=g;w-=i;w*=j;var x=c.x,y=c.y+v+d*n+(q+1)*e;if(w<0||this.e.yAxis&&w===0)this.renderTextAt("middle",true,x+10,y+q/2+v,this.e.label(b[d]));else{m||(w+=t/s);var B=r||this.e.color.call(this,b[d]);if(this.e.border){a.beginPath();a.fillStyle=
|
||||
B;this.o(a,x,y,q,p,s,w,0);a.lineTo(x,0);a.fill();a.fillStyle="#000000";a.globalAlpha=0.37;a.beginPath();this.o(a,x,y,q,p,s,w,0);a.fill()}a.globalAlpha=this.e.alpha.call(this,b[d]);a.fillStyle=r||this.e.color.call(this,b[d]);a.beginPath();var z=this.o(a,x,y,q,p,s,w,this.e.border?1:0);if(r&&!u)a.lineTo(c.x+h,y+(this.e.border?1:0));a.fill();a.globalAlpha=1;if(u!=false){var A=this.G(a,c.x,y+q,c.x+s*w+2,y,u,B,"x");a.fillStyle=A.gradient;a.beginPath();z=this.o(a,x,y+A.offset,q-A.offset*2,p,s,w,A.offset);
|
||||
a.fill();a.globalAlpha=1}this.renderTextAt("middle",false,z[0]+3,parseInt(y+(z[1]-y)/2,10),this.e.label(b[d]));f.addRect(b[d].id,[x,y,z[0],z[1]],e)}}},o:function(a,b,c,d,e,f,g,i){var j=0;if(e>f*g){var k=(e-f*g)/e;j=-Math.asin(k)+Math.PI/2}a.moveTo(b,c+i);var h=b+f*g-e-(e?0:i);e<f*g&&a.lineTo(h,c+i);f=c+e;e&&a.arc(h,f,e-i,-Math.PI/2+j,0,false);var m=c+d-e-(e?0:i),l=h+e-(e?i:0);a.lineTo(l,m);var n=h;e&&a.arc(n,m,e-i,0,Math.PI/2-j,false);var o=c+d-i;a.lineTo(b,o);a.lineTo(b,c+i);return[l,o]},$:function(a,
|
||||
b,c,d,e,f,g){this.xa(a,b,c,d,e,f);this.ya(a,b,c,d,g)},ya:function(a,b,c,d,e){if(this.e.yAxis){var f=c.x-0.5,g=d.y+0.5,i=c.y;this.i(a,f,g,f,i,this.e.yAxis.color,1);for(a=0;a<b.length;a++)this.renderTextAt("middle",0,0,i+e/2+a*e,this.e.yAxis.template(b[a]),"dhx_axis_item_y",c.x-5);this.oa(c,d)}},xa:function(a,b,c,d,e,f){var g,i={},j=this.e.xAxis;if(j){b=d.y+0.5;var k=c.x-0.5,h=d.x-0.5;this.i(a,k,b,h,b,j.color,1);if(j.step)g=parseFloat(j.step);if(typeof j.step=="undefined"||typeof j.start=="undefined"||
|
||||
typeof j.end=="undefined"){i=this.V(e,f);e=i.start;f=i.end;g=i.step;this.e.xAxis.end=f;this.e.xAxis.start=e;this.e.xAxis.step=g}if(g!==0){for(var m=(h-k)*g/(f-e),l=0,n=e;n<=f;n+=g){if(i.fixNum)n=parseFloat((new Number(n)).toFixed(i.fixNum));var o=Math.floor(k+l*m)+0.5;n!=e&&j.lines&&this.i(a,o,b,o,c.y,this.e.xAxis.color,0.2);this.renderTextAt(false,true,o,b+2,j.template(n.toString()),"dhx_axis_item_x");l++}this.renderTextAt(true,false,k,d.y+this.e.padding.bottom-3,this.e.xAxis.title,"dhx_axis_title_x",
|
||||
d.x-c.x);j.lines&&this.i(a,k,c.y-0.5,h,c.y-0.5,this.e.xAxis.color,0.2)}}}};
|
||||
dhtmlx.chart.stackedBarH={pvt_render_stackedBarH:function(a,b,c,d,e,f){var g,i,j,k,h=d.x-c.x,m=!!this.e.yAxis;i=this.Q(b);g=i.max;i=i.min;var l=Math.floor((d.y-c.y)/b.length);e||this.$(a,b,c,d,i,g,l);if(m){g=parseFloat(this.e.xAxis.end);i=parseFloat(this.e.xAxis.start)}j=this.z(i,g);k=j[0];j=j[1];var n=k?h/k:10;if(!m){var o=10;n=k?(h-o)/k:10}k=parseInt(this.e.width,10);if(k+4>l)k=l-4;var s=Math.floor((l-k)/2),t=0,q=false,v=this.e.gradient;q=false;if(v=this.e.gradient)q=true;m||this.i(a,c.x-0.5,c.y,
|
||||
c.x-0.5,d.y,"#000000",1);for(d=0;d<b.length;d++){if(!e)b[d].$startX=c.x;var p=parseFloat(this.e.value(b[d]));if(p>g)p=g;p-=i;p*=j;var u=c.x,r=c.y+s+d*l;if(e)u=b[d].$startX||u;if(p<0||this.e.yAxis&&p===0)this.renderTextAt("middle",true,u+10,r+k/2,this.e.label(b[d]));else{m||(p+=o/n);var w=this.e.color.call(this,b[d]);if(this.e.border){a.beginPath();a.fillStyle=w;this.o(a,u,r,k,t,n,p,0);a.lineTo(u,0);a.fill();a.fillStyle="#000000";a.globalAlpha=0.37;a.beginPath();this.o(a,u,r,k,t,n,p,0);a.fill()}a.globalAlpha=
|
||||
1;a.globalAlpha=this.e.alpha.call(this,b[d]);a.fillStyle=this.e.color.call(this,b[d]);a.beginPath();var x=this.o(a,u,r,k,t,n,p,this.e.border?1:0);if(v&&!q)a.lineTo(c.x+h,r+(this.e.border?1:0));a.fill();if(q!=false){w=this.G(a,u,r+k,u,r,q,w,"x");a.fillStyle=w.gradient;a.beginPath();x=this.o(a,u,r,k,t,n,p,0);a.fill();a.globalAlpha=1}this.renderTextAt("middle",true,b[d].$startX+(x[0]-b[d].$startX)/2-1,r+(x[1]-r)/2,this.e.label(b[d]));f.addRect(b[d].id,[b[d].$startX,r,x[0],x[1]],e);b[d].$startX=x[0]}}}};
|
||||
dhtmlx.chart.stackedBar={pvt_render_stackedBar:function(a,b,c,d,e,f){var g,i,j,k=d.y-c.y;j=!!this.e.yAxis;var h=!!this.e.xAxis;i=this.Q(b);g=i.max;i=i.min;var m=Math.floor((d.x-c.x)/b.length);e||this.N(a,b,c,d,i,g,m);if(j){g=parseFloat(this.e.yAxis.end);i=parseFloat(this.e.yAxis.start)}g=this.z(i,g);j=g[0];g=g[1];j=j?k/j:10;var l=parseInt(this.e.width,10);if(l+4>m)l=m-4;var n=Math.floor((m-l)/2),o=this.e.gradient?this.e.gradient:false;h||this.i(a,c.x,d.y+0.5,d.x,d.y+0.5,"#000000",1);for(h=0;h<b.length;h++){var s=
|
||||
parseFloat(this.e.value(b[h]));if(s){e||(s-=i);s*=g;var t=c.x+n+h*m,q=d.y;if(e)q=b[h].$startY||q;if(!(q<c.y+1))if(s<0||this.e.yAxis&&s===0)this.renderTextAt(true,true,t+Math.floor(l/2),q,this.e.label(b[h]));else{var v=this.e.color.call(this,b[h]);if(this.e.border){a.beginPath();a.fillStyle=v;this.I(a,t-1,q,l+2,j,s,0,c.y);a.lineTo(t,q);a.fill();a.fillStyle="#000000";a.globalAlpha=0.37;a.beginPath();this.I(a,t-1,q,l+2,j,s,0,c.y);a.fill()}a.globalAlpha=this.e.alpha.call(this,b[h]);a.fillStyle=this.e.color.call(this,
|
||||
b[h]);a.beginPath();var p=this.I(a,t,q,l,j,s,this.e.border?1:0,c.y);a.fill();a.globalAlpha=1;if(o){v=this.G(a,t,q,t+l,p[1],o,v,"y");a.fillStyle=v.gradient;a.beginPath();p=this.I(a,t+v.offset,q,l-v.offset*2,j,s,this.e.border?1:0,c.y);a.fill();a.globalAlpha=1}this.renderTextAt(false,true,t+Math.floor(l/2),p[1]+(q-p[1])/2-7,this.e.label(b[h]));f.addRect(b[h].id,[t,p[1],p[0],b[h].$startY||q],e);b[h].$startY=this.e.border?p[1]+1:p[1]}}}},I:function(a,b,c,d,e,f,g,i){a.moveTo(b,c);f=c-e*f+g;if(f<i)f=i;a.lineTo(b,
|
||||
f);e=b+d;f=f;a.lineTo(e,f);var j=b+d;a.lineTo(j,c);a.lineTo(b,c);return[j,f-2*g]}};
|
||||
dhtmlx.chart.line={pvt_render_line:function(a,b,c,d,e,f){e=this.C(a,b,c,d,e);var g=Math.floor(e.cellWidth/2);if(b.length)for(var i=this.p(b[0],c,d,e),j=this.e.offset?c.x+e.cellWidth*0.5:c.x,k=j,h=1;h<=b.length;h++){var m=Math.floor(e.cellWidth*h)-0.5+k;if(b.length!=h){var l=this.p(b[h],c,d,e);this.i(a,j,i,m,l,this.e.line.color(b[h-1]),this.e.line.width)}this.M(a,j,i,b[h-1],!!this.e.offset);f.addRect(b[h-1].id,[j-g,i-g,j+g,i+g]);i=l;j=m}},M:function(a,b,c,d,e){var f=parseInt(this.e.item.radius,10);
|
||||
a.lineWidth=parseInt(this.e.item.borderWidth,10);a.fillStyle=this.e.item.color(d);a.strokeStyle=this.e.item.borderColor(d);a.beginPath();a.arc(b,c,f,0,Math.PI*2,true);a.fill();a.stroke();e&&this.renderTextAt(false,true,b,c-f-this.e.labelOffset,this.e.label(d))},p:function(a,b,c,d){var e=d.minValue,f=d.maxValue,g=d.unit,i=d.valueFactor;a=this.e.value(a);i=(parseFloat(a)-e)*i;this.e.yAxis||(i+=d.startValue/g);d=c.y-Math.floor(g*i);if(i<0)d=c.y;if(a>f)d=b.y;if(a<e)d=c.y;return d},C:function(a,b,c,d,
|
||||
e){var f={};f.totalHeight=d.y-c.y;f.cellWidth=Math.round((d.x-c.x)/(!this.e.offset?b.length-1:b.length));var g=!!this.e.yAxis,i=this.e.view.indexOf("stacked")!=-1?this.Q(b):this.O();f.maxValue=i.max;f.minValue=i.min;e||this.N(a,b,c,d,f.minValue,f.maxValue,f.cellWidth);if(g){f.maxValue=parseFloat(this.e.yAxis.end);f.minValue=parseFloat(this.e.yAxis.start)}b=this.z(f.minValue,f.maxValue);a=b[0];f.valueFactor=b[1];f.unit=a?f.totalHeight/a:10;f.startValue=0;if(!g){f.startValue=f.unit>10?f.unit:10;f.unit=
|
||||
a?(f.totalHeight-f.startValue)/a:10}return f}};
|
||||
dhtmlx.chart.bar={pvt_render_bar:function(a,b,c,d,e,f){var g,i,j,k,h=d.y-c.y,m=!!this.e.yAxis,l=!!this.e.xAxis;i=this.O();g=i.max;i=i.min;var n=Math.floor((d.x-c.x)/b.length);!e&&!(this.e.origin!="auto"&&!m)&&this.N(a,b,c,d,i,g,n);if(m){g=parseFloat(this.e.yAxis.end);i=parseFloat(this.e.yAxis.start)}j=this.z(i,g);k=j[0];j=j[1];var o=k?h/k:k;if(!m&&!(this.e.origin!="auto"&&l)){var s=10;o=k?(h-s)/k:s}!e&&this.e.origin!="auto"&&!m&&this.e.origin>i&&this.da(a,b,c,d,n,d.y-o*(this.e.origin-i));h=parseInt(this.e.width,
|
||||
10);if(this.h&&h*this.h.length+4>n)h=n/this.h.length-4;k=Math.floor((n-h*this.h.length)/2);var t=typeof this.e.radius!="undefined"?parseInt(this.e.radius,10):Math.round(h/5),q=false,v=this.e.gradient;if(v&&typeof v!="function"){q=v;v=false}else if(v){v=a.createLinearGradient(0,d.y,0,c.y);this.e.gradient(v)}l||this.i(a,c.x,d.y+0.5,d.x,d.y+0.5,"#000000",1);for(var p=0;p<b.length;p++){var u=parseFloat(this.e.value(b[p]));if(u>g)u=g;u-=i;u*=j;var r=c.x+k+p*n+(h+1)*e,w=d.y;if(u<0||this.e.yAxis&&u===0&&
|
||||
!(this.e.origin!="auto"&&this.e.origin>i))this.renderTextAt(true,true,r+Math.floor(h/2),w,this.e.label(b[p]));else{if(!m&&!(this.e.origin!="auto"&&l))u+=s/o;var x=v||this.e.color.call(this,b[p]);this.e.border&&this.va(a,r,w,h,i,t,o,u,x);a.globalAlpha=this.e.alpha.call(this,b[p]);var y=this.ua(a,c,r,w,h,i,t,o,u,x,v,q);a.globalAlpha=1;q&&this.wa(a,r,w,h,i,t,o,u,x,q);y[0]!=r?this.renderTextAt(false,true,r+Math.floor(h/2),y[1],this.e.label(b[p])):this.renderTextAt(true,true,r+Math.floor(h/2),y[3],this.e.label(b[p]));
|
||||
f.addRect(b[p].id,[r,y[3],y[2],y[1]],e)}}},K:function(a,b,c,d,e,f,g){var i=this.e.xAxis,j=c;if(i&&this.e.origin!="auto"&&this.e.origin>g){c-=(this.e.origin-g)*e;j=c;d-=this.e.origin-g;if(d<0){d*=-1;a.translate(b+f,c);a.rotate(Math.PI);c=b=0}c-=0.5}return{value:d,x0:b,y0:c,start:j}},ua:function(a,b,c,d,e,f,g,i,j,k,h,m){a.save();a.fillStyle=k;var l=this.K(a,c,d,j,i,e,f);e=this.H(a,l.x0,l.y0,e,g,i,l.value,this.e.border?1:0);if(h&&!m)a.lineTo(l.x0+(this.e.border?1:0),b.y);a.fill();a.restore();a=l.x0;
|
||||
b=l.x0!=c?c+e[0]:e[0];d=l.x0!=c?l.start-e[1]:d;c=l.x0!=c?l.start:e[1];return[a,d,b,c]},va:function(a,b,c,d,e,f,g,i,j){a.save();b=this.K(a,b,c,i,g,d,e);a.fillStyle=j;this.H(a,b.x0,b.y0,d,f,g,b.value,0);a.lineTo(b.x0,0);a.fill();a.fillStyle="#000000";a.globalAlpha=0.37;this.H(a,b.x0,b.y0,d,f,g,b.value,0);a.fill();a.restore()},wa:function(a,b,c,d,e,f,g,i,j,k){a.save();b=this.K(a,b,c,i,g,d,e);j=this.G(a,b.x0,b.y0,b.x0+d,b.y0-g*b.value+2,k,j,"y");a.fillStyle=j.gradient;this.H(a,b.x0+j.offset,b.y0,d-j.offset*
|
||||
2,f,g,b.value,j.offset);a.fill();a.restore()},H:function(a,b,c,d,e,f,g,i){a.beginPath();var j=0;if(e>f*g){var k=(e-f*g)/e;j=-Math.acos(k)+Math.PI/2}a.moveTo(b+i,c);var h=c-Math.floor(f*g)+e+(e?0:i);e<f*g&&a.lineTo(b+i,h);f=b+e;e&&a.arc(f,h,e-i,-Math.PI+j,-Math.PI/2,false);g=b+d-e-(e?0:i);f=h-e+(e?i:0);a.lineTo(g,f);h=h;e&&a.arc(g,h,e-i,-Math.PI/2,0-j,false);d=b+d-i;a.lineTo(d,c);a.lineTo(b+i,c);return[d,f]}};
|
||||
dhtmlx.chart.pie={pvt_render_pie:function(a,b,c,d,e,f){this.na(a,b,c,d,1,f)},na:function(a,b,c,d,e,f){var g=0,i=this.Ga(c,d);c=this.e.radius?this.e.radius:i.radius;this.max(this.e.value);for(var j=[],k=[],h=0,m=0;m<b.length;m++)g+=parseFloat(this.e.value(b[m]));for(m=0;m<b.length;m++){k[m]=parseFloat(this.e.value(b[m]));j[m]=Math.PI*2*(g?(k[m]+h)/g:1/b.length);h+=k[m]}d=this.e.x?this.e.x:i.x;var l=this.e.y?this.e.y:i.y;e==1&&this.e.shadow&&this.sa(a,d,l,c);l/=e;var n=-Math.PI/2;a.scale(1,e);for(m=
|
||||
0;m<b.length;m++)if(k[m]){a.lineWidth=2;a.beginPath();a.moveTo(d,l);alpha1=-Math.PI/2+j[m]-1.0E-4;a.arc(d,l,c,n,alpha1,false);a.lineTo(d,l);var o=this.e.color.call(this,b[m]);a.fillStyle=o;a.strokeStyle=this.e.lineColor(b[m]);a.stroke();a.fill();this.e.pieInnerText&&this.ba(d,l,5*c/6,n,alpha1,e,this.e.pieInnerText(b[m],g),true);this.e.label&&this.ba(d,l,c+this.e.labelOffset,n,alpha1,e,this.e.label(b[m]));if(e!=1){this.W(a,d,l,n,alpha1,c,true);a.fillStyle="#000000";a.globalAlpha=0.2;this.W(a,d,l,n,
|
||||
alpha1,c,false);a.globalAlpha=1;a.fillStyle=o}f.addSector(b[m].id,n,alpha1,d,l,c,e);n=alpha1}if(this.e.gradient){b=e!=1?d+c/3:d;f=e!=1?l+c/3:l;this.bb(a,d,l,c,b,f)}a.scale(1,1/e)},Ga:function(a,b){var c=b.x-a.x,d=b.y-a.y;b=a.x+c/2;a=a.y+d/2;var e=Math.min(c/2,d/2);return{x:b,y:a,radius:e}},W:function(a,b,c,d,e,f,g){a.lineWidth=1;if(d<=0&&e>=0||d>=0&&e<=Math.PI||d<=Math.PI&&e>=Math.PI){if(d<=0&&e>=0){d=0;g=false;this.ca(a,b,c,f,d,e)}if(d<=Math.PI&&e>=Math.PI){e=Math.PI;g=false;this.ca(a,b,c,f,d,e)}var i=
|
||||
(this.e.height||Math.floor(f/4))/this.e.cant;a.beginPath();a.arc(b,c,f,d,e,false);a.lineTo(b+f*Math.cos(e),c+f*Math.sin(e)+i);a.arc(b,c+i,f,e,d,true);a.lineTo(b+f*Math.cos(d),c+f*Math.sin(d));a.fill();g&&a.stroke()}},ca:function(a,b,c,d,e,f){a.beginPath();a.arc(b,c,d,e,f,false);a.stroke()},sa:function(a,b,c,d){for(var e=["#676767","#7b7b7b","#a0a0a0","#bcbcbc","#d1d1d1","#d6d6d6"],f=e.length-1;f>-1;f--){a.beginPath();a.fillStyle=e[f];a.arc(b+2,c+2,d+f,0,Math.PI*2,true);a.fill()}},Fa:function(a){a.addColorStop(0,
|
||||
"#ffffff");a.addColorStop(0.7,"#7a7a7a");a.addColorStop(1,"#000000");return a},bb:function(a,b,c,d,e,f){a.globalAlpha=0.3;a.beginPath();var g;if(typeof this.e.gradient!="function"){g=a.createRadialGradient(e,f,d/4,b,c,d);g=this.Fa(g)}else g=this.e.gradient(g);a.fillStyle=g;a.arc(b,c,d,0,Math.PI*2,true);a.fill();a.globalAlpha=1},ba:function(a,b,c,d,e,f,g,i){var j=this.renderText(0,0,g,0,1);if(j){var k=j.scrollWidth;j.style.width=k+"px";if(k>a)k=a;var h=8;if(i)h=k/1.8;var m=d+(e-d)/2;c-=(h-8)/2;var l=
|
||||
-h,n=-8,o="left";if(m>=Math.PI/2&&m<Math.PI){l=-k-l+1;o="right"}if(m<=3*Math.PI/2&&m>=Math.PI){l=-k-l+1;o="right"}d=(b+Math.floor(c*Math.sin(m)))*f+n;h=a+Math.floor((c+h/2)*Math.cos(m))+l;var s=e<Math.PI/2+0.01,t=m<Math.PI/2;if(t&&s)h=Math.max(h,a+3);else if(!t&&!s)h=Math.min(h,a-k);if(!i&&f<1&&d>b*f)d+=this.e.height||Math.floor(c/4);j.style.top=d+"px";j.style.left=h+"px";j.style.width=k+"px";j.style.textAlign=o;j.style.whiteSpace="nowrap"}}};
|
||||
dhtmlx.chart.pie3D={pvt_render_pie3D:function(a,b,c,d,e,f){this.na(a,b,c,d,this.e.cant,f)}};
|
||||
dhtmlx.Template={J:{},empty:function(){return""},setter:function(a,b){return dhtmlx.Template.fromHTML(b)},obj_setter:function(a,b){var c=dhtmlx.Template.setter(a,b),d=this;return function(){return c.apply(d,arguments)}},fromHTML:function(a){if(typeof a=="function")return a;if(this.J[a])return this.J[a];a=(a||"").toString();a=a.replace(/[\r\n]+/g,"\\n");a=a.replace(/\{obj\.([^}?]+)\?([^:]*):([^}]*)\}/g,'"+(obj.$1?"$2":"$3")+"');a=a.replace(/\{common\.([^}\(]*)\}/g,'"+common.$1+"');a=a.replace(/\{common\.([^\}\(]*)\(\)\}/g,
|
||||
'"+(common.$1?common.$1(obj):"")+"');a=a.replace(/\{obj\.([^}]*)\}/g,'"+obj.$1+"');a=a.replace(/#([a-z0-9_]+)#/gi,'"+obj.$1+"');a=a.replace(/\{obj\}/g,'"+obj+"');a=a.replace(/\{-obj/g,"{obj");a=a.replace(/\{-common/g,"{common");a='return "'+a+'";';return this.J[a]=Function("obj","common",a)}};
|
||||
dhtmlx.Type={add:function(a,b){if(!a.types&&a.prototype.types)a=a.prototype;var c=b.name||"default";this.T(b);this.T(b,"edit");this.T(b,"loading");a.types[c]=dhtmlx.extend(dhtmlx.extend({},a.types[c]||this.ta),b);return c},ta:{css:"default",template:function(){return""},template_edit:function(){return""},template_loading:function(){return"..."},width:150,height:80,margin:5,padding:0},T:function(a,b){b="template"+(b?"_"+b:"");var c=a[b];if(c&&typeof c=="string"){if(c.indexOf("->")!=-1){c=c.split("->");
|
||||
switch(c[0]){case "html":c=dhtmlx.html.getValue(c[1]).replace(/\"/g,'\\"');break;case "http":c=(new dhtmlx.ajax).sync().get(c[1],{uid:(new Date).valueOf()}).responseText;break;default:break}}a[b]=dhtmlx.Template.fromHTML(c)}}};
|
||||
dhtmlx.SingleRender={k:function(){},eb:function(a){return this.type.Oa(a,this.type)+this.type.template(a,this.type)+this.type.Na},render:function(){if(!this.callEvent||this.callEvent("onBeforeRender",[this.data])){if(this.data)this.L.innerHTML=this.eb(this.data);this.callEvent&&this.callEvent("onAfterRender",[])}}};
|
||||
dhtmlx.ui.Tooltip=function(a){this.name="Tooltip";this.version="3.0";if(typeof a=="string")a={template:a};dhtmlx.extend(this,dhtmlx.Settings);dhtmlx.extend(this,dhtmlx.SingleRender);this.B(a,{type:"default",dy:0,dx:20});this.L=this.g=document.createElement("DIV");this.g.className="dhx_tooltip";dhtmlx.html.insertBefore(this.g,document.body.firstChild)};
|
||||
dhtmlx.ui.Tooltip.prototype={show:function(a,b){if(!this.Z){if(this.data!=a){this.data=a;this.render(a)}this.g.style.top=b.y+this.e.dy+"px";this.g.style.left=b.x+this.e.dx+"px";this.g.style.display="block"}},hide:function(){this.data=null;this.g.style.display="none"},disable:function(){this.Z=true},enable:function(){this.Z=false},types:{"default":dhtmlx.Template.fromHTML("{obj.id}")},template_item_start:dhtmlx.Template.empty,template_item_end:dhtmlx.Template.empty};
|
||||
dhtmlx.AutoTooltip={tooltip_setter:function(a,b){var c=new dhtmlx.ui.Tooltip(b);this.attachEvent("onMouseMove",function(d,e){c.show(this.get(d),dhtmlx.html.pos(e))});this.attachEvent("onMouseOut",function(){c.hide()});this.attachEvent("onMouseMoving",function(){c.hide()});return c}};dhtmlx.DataStore=function(){this.name="DataStore";dhtmlx.extend(this,dhtmlx.EventSystem);this.setDriver("xml");this.pull={};this.order=dhtmlx.toArray();this.gb=false};
|
||||
dhtmlx.DataStore.prototype={setDriver:function(a){this.driver=dhtmlx.DataDriver[a]},qa:function(a){if(a.item){if(!(a.item instanceof Array))a.item=[a.item];for(var b=0;b<a.item.length;b++){var c=a.item[b],d=this.id(c);a.item[b]=d;this.pull[d]=c;c.parent=a.id;c.level=a.level+1;this.qa(c)}}},Wa:function(a){for(var b=this.driver.getInfo(a),c=this.driver.getRecords(a),d=(b.u||0)*1,e=0,f=0;f<c.length;f++){var g=this.driver.getDetails(c[f]),i=this.id(g);if(!this.pull[i]){this.order[e+d]=i;e++}this.pull[i]=
|
||||
g;if(this.gb){g.level=1;this.qa(g)}}for(f=0;f<b.w;f++)if(!this.order[f]){i=dhtmlx.uid();g={id:i,$template:"loading"};this.pull[i]=g;this.order[f]=i}this.callEvent("onStoreLoad",[this.driver,a]);this.refresh()},id:function(a){return a.id||(a.id=dhtmlx.uid())},get:function(a){return this.pull[a]},set:function(a,b){this.pull[a]=b;this.refresh()},refresh:function(a){a?this.callEvent("onStoreUpdated",[a,this.pull[a],"update"]):this.callEvent("onStoreUpdated",[null,null,null])},getRange:function(a,b){if(arguments.length){a=
|
||||
this.indexById(a);b=this.indexById(b);if(a>b){var c=b;b=a;a=c}}else{a=this.min||0;b=Math.min(this.max||Infinity,this.dataCount()-1)}return this.getIndexRange(a,b)},getIndexRange:function(a,b){b=Math.min(b,this.dataCount()-1);var c=dhtmlx.toArray();for(a=a;a<=b;a++)c.push(this.get(this.order[a]));return c},dataCount:function(){return this.order.length},exists:function(a){return!!this.pull[a]},move:function(a,b){if(!(a<0||b<0)){var c=this.idByIndex(a),d=this.get(c);this.order.removeAt(a);this.order.insertAt(c,
|
||||
Math.min(this.order.length,b));this.callEvent("onStoreUpdated",[c,d,"move"])}},add:function(a,b){var c=this.id(a),d=this.dataCount();if(dhtmlx.isNotDefined(b)||b<0)b=d;if(b>d)b=Math.min(this.order.length,b);if(this.callEvent("onbeforeAdd",[c,b])){if(this.exists(c))return null;this.pull[c]=a;this.order.insertAt(c,b);if(this.m){var e=this.m.length;if(!b&&this.order.length)e=0;this.m.insertAt(c,e)}this.callEvent("onafterAdd",[c,b]);this.callEvent("onStoreUpdated",[c,a,"add"]);return c}},remove:function(a){if(a instanceof
|
||||
Array)for(var b=0;b<a.length;b++)this.remove(a[b]);else if(this.callEvent("onbeforedelete",[a])){if(!this.exists(a))return null;b=this.get(a);this.order.remove(a);this.m&&this.m.remove(a);delete this.pull[a];this.callEvent("onafterdelete",[a]);this.callEvent("onStoreUpdated",[a,b,"delete"])}},clearAll:function(){this.pull={};this.order=dhtmlx.toArray();this.m=null;this.callEvent("onClearAll",[]);this.refresh()},idByIndex:function(a){return this.order[a]},indexById:function(a){return a=this.order.find(a)},
|
||||
next:function(a,b){return this.order[this.indexById(a)+(b||1)]},first:function(){return this.order[0]},last:function(){return this.order[this.order.length-1]},previous:function(a,b){return this.order[this.indexById(a)-(b||1)]},sort:function(a,b,c){var d=a;if(typeof a=="function")d={as:a,dir:b};else if(typeof a=="string")d={by:a,dir:b,as:c};var e=[d.by,d.dir,d.as];if(this.callEvent("onbeforesort",e)){if(this.order.length){var f=dhtmlx.sort.create(d),g=this.getRange(this.first(),this.last());g.sort(f);
|
||||
this.order=g.map(function(i){return this.id(i)},this)}this.refresh();this.callEvent("onaftersort",e)}},filter:function(a,b){if(this.m){this.order=this.m;delete this.m}if(a){var c=a;if(typeof a=="string"){a=dhtmlx.Template.setter(0,a);c=function(e,f){return a(e).toLowerCase().indexOf(f)!=-1}}b=(b||"").toString().toLowerCase();var d=dhtmlx.toArray();this.order.each(function(e){c(this.get(e),b)&&d.push(e)},this);this.m=this.order;this.order=d}this.refresh()},each:function(a,b){for(var c=0;c<this.order.length;c++)a.call(b||
|
||||
this,this.get(this.order[c]))},provideApi:function(a,b){b&&this.mapEvent({onbeforesort:a,onaftersort:a,onbeforeadd:a,onafteradd:a,onbeforedelete:a,onafterdelete:a});for(var c=["sort","add","remove","exists","idByIndex","indexById","get","set","refresh","dataCount","filter","next","previous","clearAll","first","last"],d=0;d<c.length;d++)a[c[d]]=dhtmlx.methodPush(this,c[d])}};
|
||||
dhtmlx.sort={create:function(a){return dhtmlx.sort.dir(a.dir,dhtmlx.sort.by(a.by,a.as))},as:{"int":function(a,b){a*=1;b*=1;return a>b?1:a<b?-1:0},string_strict:function(a,b){a=a.toString();b=b.toString();return a>b?1:a<b?-1:0},string:function(a,b){a=a.toString().toLowerCase();b=b.toString().toLowerCase();return a>b?1:a<b?-1:0}},by:function(a,b){if(typeof b!="function")b=dhtmlx.sort.as[b||"string"];a=dhtmlx.Template.setter(0,a);return function(c,d){return b(a(c),a(d))}},dir:function(a,b){if(a=="asc")return b;
|
||||
return function(c,d){return b(c,d)*-1}}};
|
||||
dhtmlx.Group={k:function(){this.data.attachEvent("onStoreLoad",dhtmlx.bind(function(){this.e.group&&this.group(this.e.group,false)},this));this.attachEvent("onBeforeRender",dhtmlx.bind(function(a){if(this.e.sort){a.block();a.sort(this.e.sort);a.unblock()}},this));this.attachEvent("onBeforeSort",dhtmlx.bind(function(){this.e.sort=null},this))},Ja:function(a,b){a.attachEvent("onClearAll",dhtmlx.bind(function(){this.ungroup(false)},b))},sum:function(a,b){a=dhtmlx.Template.setter(0,a);b=b||this.data;
|
||||
var c=0;b.each(function(d){c+=a(d)*1});return c},min:function(a,b){a=dhtmlx.Template.setter(0,a);b=b||this.data;var c=Infinity;b.each(function(d){if(a(d)*1<c)c=a(d)*1});return c*1},max:function(a,b){a=dhtmlx.Template.setter(0,a);b=b||this.data;var c=-Infinity;b.each(function(d){if(a(d)*1>c)c=a(d)*1});return c},cb:function(a){var b=function(j,k){j=dhtmlx.Template.setter(0,j);return j(k[0])},c=dhtmlx.Template.setter(0,a.by);a.map[c]||(a.map[c]=[c,b]);var d={},e=[];this.data.each(function(j){var k=c(j);
|
||||
if(!d[k]){e.push({id:k});d[k]=dhtmlx.toArray()}d[k].push(j)});for(var f in a.map){var g=a.map[f][1]||b;if(typeof g!="function")g=this[g];for(var i=0;i<e.length;i++)e[i][f]=g.call(this,a.map[f][0],d[e[i].id])}this.ja=this.data;this.data=new dhtmlx.DataStore;this.data.provideApi(this,true);this.Ja(this.data,this);this.parse(e,"json")},group:function(a,b){this.ungroup(false);this.cb(a);b!==false&&this.render()},ungroup:function(a){if(this.ja){this.data=this.ja;this.data.provideApi(this,true)}a!==false&&
|
||||
this.render()},group_setter:function(a,b){return b},sort_setter:function(a,b){if(typeof b!="object")b={by:b};this.n(b,{as:"string",dir:"asc"});return b}};dhtmlx.KeyEvents={k:function(){dhtmlx.event(this.g,"keypress",this.Ta,this)},Ta:function(a){a=a||event;var b=a.which||a.keyCode;this.callEvent(this.hb?"onEditKeyPress":"onKeyPress",[b,a.ctrlKey,a.shiftKey,a])}};
|
||||
dhtmlx.MouseEvents={k:function(){if(this.on_click){dhtmlx.event(this.g,"click",this.Qa,this);dhtmlx.event(this.g,"contextmenu",this.Ra,this)}this.on_dblclick&&dhtmlx.event(this.g,"dblclick",this.Sa,this);if(this.on_mouse_move){dhtmlx.event(this.g,"mousemove",this.la,this);dhtmlx.event(this.g,dhtmlx.r?"mouseleave":"mouseout",this.la,this)}},Qa:function(a){return this.R(a,this.on_click,"ItemClick")},Sa:function(a){return this.R(a,this.on_dblclick,"ItemDblClick")},Ra:function(a){var b=dhtmlx.html.locate(a,
|
||||
this.q);if(b&&!this.callEvent("onBeforeContextMenu",[b,a]))return dhtmlx.html.preventEvent(a)},la:function(a){if(dhtmlx.r)a=document.createEventObject(event);this.ia&&window.clearTimeout(this.ia);this.callEvent("onMouseMoving",[a]);this.ia=window.setTimeout(dhtmlx.bind(function(){a.type=="mousemove"?this.Ua(a):this.Va(a)},this),500)},Ua:function(a){this.R(a,this.on_mouse_move,"MouseMove")||this.callEvent("onMouseOut",[a||event])},Va:function(a){this.callEvent("onMouseOut",[a||event])},R:function(a,
|
||||
b,c){a=a||event;for(var d=a.target||a.srcElement,e="",f=null,g=false;d&&d.parentNode;){if(!g&&d.getAttribute)if(f=d.getAttribute(this.q)){d.getAttribute("userdata")&&this.callEvent("onLocateData",[f,d]);if(!this.callEvent("on"+c,[f,a,d]))return;g=true}if(e=d.className){e=e.split(" ");e=e[0]||e[1];if(b[e])return b[e].call(this,a,f,d)}d=d.parentNode}return g}};
|
||||
dhtmlx.Settings={k:function(){this.e=this.config={}},define:function(a,b){if(typeof a=="object")return this.ma(a);return this.Y(a,b)},Y:function(a,b){var c=this[a+"_setter"];return this.e[a]=c?c.call(this,a,b):b},ma:function(a){if(a)for(var b in a)this.Y(b,a[b])},B:function(a,b){var c=dhtmlx.extend({},b);typeof a=="object"&&!a.tagName&&dhtmlx.extend(c,a);this.ma(c)},n:function(a,b){for(var c in b)switch(typeof a[c]){case "object":a[c]=this.n(a[c]||{},b[c]);break;case "undefined":a[c]=b[c];break;default:break}return a},
|
||||
Xa:function(a,b,c){if(typeof a=="object"&&!a.tagName)a=a.container;this.g=dhtmlx.toNode(a);if(!this.g&&c)this.g=c(a);this.g.className+=" "+b;this.g.onselectstart=function(){return false};this.L=this.g},ab:function(a){if(typeof a=="object")return this.type_setter("type",a);this.type=dhtmlx.extend({},this.types[a]);this.customize()},customize:function(a){a&&dhtmlx.extend(this.type,a);this.type.Oa=dhtmlx.Template.fromHTML(this.template_item_start(this.type));this.type.Na=this.template_item_end(this.type);
|
||||
this.render()},type_setter:function(a,b){this.ab(typeof b=="object"?dhtmlx.Type.add(this,b):b);return b},template_setter:function(a,b){return this.type_setter("type",{template:b})},css_setter:function(a,b){this.g.className+=" "+b;return b}};dhtmlx.compat=function(a,b){dhtmlx.compat[a]&&dhtmlx.compat[a](b)};
|
||||
(function(){if(!window.dhtmlxError){var a=function(){};window.dhtmlxError={catchError:a,throwError:a};window.convertStringToBoolean=function(c){return!!c};window.dhtmlxEventable=function(c){dhtmlx.extend(c,dhtmlx.EventSystem)};var b={getXMLTopNode:function(){},doXPath:function(c){return dhtmlx.DataDriver.xml.xpath(this.xml,c)},xmlDoc:{responseXML:true}};dhtmlx.compat.dataProcessor=function(c){var d="_sendData",e="_in_progress",f="_tMode",g="_waitMode";c[d]=function(i,j){if(i){if(j)this[e][j]=(new Date).valueOf();
|
||||
if(!this.callEvent("onBeforeDataSending",j?[j,this.getState(j)]:[]))return false;var k=this,h=this.serverProcessor;this[f]!="POST"?dhtmlx.ajax().get(h+(h.indexOf("?")!=-1?"&":"?")+this.serialize(i,j),"",function(m,l){b.xml=dhtmlx.DataDriver.xml.checkResponse(m,l);k.afterUpdate(k,null,null,null,b)}):dhtmlx.ajax().post(h,this.serialize(i,j),function(m,l){b.xml=dhtmlx.DataDriver.xml.checkResponse(m,l);k.afterUpdate(k,null,null,null,b)});this[g]++}}}}})();if(!dhtmlx.attaches)dhtmlx.attaches={};
|
||||
dhtmlx.attaches.attachAbstract=function(a,b){var c=document.createElement("DIV");c.id="CustomObject_"+dhtmlx.uid();c.style.width="100%";c.style.height="100%";c.cmp="grid";document.body.appendChild(c);this.attachObject(c.id);b.container=c.id;var d=this.vs[this.av];d.grid=new window[a](b);d.gridId=c.id;d.gridObj=c;d.grid.setSizes=function(){this.resize?this.resize():this.render()};var e="_viewRestore";return this.vs[this[e]()].grid};
|
||||
dhtmlx.attaches.attachDataView=function(a){return this.attachAbstract("dhtmlXDataView",a)};dhtmlx.attaches.attachChart=function(a){return this.attachAbstract("dhtmlXChart",a)};dhtmlx.compat.layout=function(){};dhtmlx.ajax=function(a,b,c){if(arguments.length!==0){var d=new dhtmlx.ajax;if(c)d.master=c;d.get(a,null,b)}if(!this.getXHR)return new dhtmlx.ajax;return this};
|
||||
dhtmlx.ajax.prototype={getXHR:function(){return dhtmlx.r?new ActiveXObject("Microsoft.xmlHTTP"):new XMLHttpRequest},send:function(a,b,c){var d=this.getXHR();if(typeof c=="function")c=[c];if(typeof b=="object"){var e=[];for(var f in b)e.push(f+"="+encodeURIComponent(b[f]));b=e.join("&")}if(b&&!this.post){a=a+(a.indexOf("?")!=-1?"&":"?")+b;b=null}d.open(this.post?"POST":"GET",a,!this.pa);this.post&&d.setRequestHeader("Content-type","application/x-www-form-urlencoded");if(!this.pa){var g=this;d.onreadystatechange=
|
||||
function(){if(!d.readyState||d.readyState==4){if(c&&g)for(var i=0;i<c.length;i++)if(c[i])c[i].call(g.master||g,d.responseText,d.responseXML,d);c=d=g=g.master=null}}}d.send(b||null);return d},get:function(a,b,c){this.post=false;return this.send(a,b,c)},post:function(a,b,c){this.post=true;return this.send(a,b,c)},sync:function(){this.pa=true;return this}};
|
||||
dhtmlx.DataLoader={k:function(){this.data=new dhtmlx.DataStore},load:function(a,b,c){this.callEvent("onXLS",[]);if(typeof b=="string"){this.data.setDriver(b);b=c}if(!this.data.feed)this.data.feed=function(d,e){if(this.F)return this.F=[d,e];else this.F=true;this.load(a+(a.indexOf("?")==-1?"?":"&")+"posStart="+d+"&count="+e,function(){var f=this.F;this.F=false;typeof f=="object"&&this.data.feed.apply(this,f)})};dhtmlx.ajax(a,[this.ka,b],this)},parse:function(a,b){this.callEvent("onXLS",[]);b&&this.data.setDriver(b);
|
||||
this.ka(a,null)},ka:function(a,b){this.data.Wa(this.data.driver.toObject(a,b));this.callEvent("onXLE",[])}};dhtmlx.DataDriver={};dhtmlx.DataDriver.json={toObject:function(a){if(typeof a=="string"){eval("dhtmlx.temp="+a);return dhtmlx.temp}return a},getRecords:function(a){if(a&&!(a instanceof Array))return[a];return a},getDetails:function(a){return a},getInfo:function(a){return{w:a.total_count||0,u:a.pos||0}}};
|
||||
dhtmlx.DataDriver.html={toObject:function(a){if(typeof a=="string"){var b=null;if(a.indexOf("<")==-1)b=dhtmlx.toNode(a);if(!b){b=document.createElement("DIV");b.innerHTML=a}return b.getElementsByTagName(this.tag)}return a},getRecords:function(a){if(a.tagName)return a.childNodes;return a},getDetails:function(a){return dhtmlx.DataDriver.xml.tagToObject(a)},getInfo:function(){return{w:0,u:0}},tag:"LI"};
|
||||
dhtmlx.DataDriver.jsarray={toObject:function(a){if(typeof a=="string"){eval("dhtmlx.temp="+a);return dhtmlx.temp}return a},getRecords:function(a){return a},getDetails:function(a){for(var b={},c=0;c<a.length;c++)b["data"+c]=a[c];return b},getInfo:function(){return{w:0,u:0}}};
|
||||
dhtmlx.DataDriver.csv={toObject:function(a){return a},getRecords:function(a){return a.split(this.row)},getDetails:function(a){a=this.stringToArray(a);for(var b={},c=0;c<a.length;c++)b["data"+c]=a[c];return b},getInfo:function(){return{w:0,u:0}},stringToArray:function(a){a=a.split(this.cell);for(var b=0;b<a.length;b++)a[b]=a[b].replace(/^[ \t\n\r]*(\"|)/g,"").replace(/(\"|)[ \t\n\r]*$/g,"");return a},row:"\n",cell:","};
|
||||
dhtmlx.DataDriver.xml={toObject:function(a,b){if(b&&(b=this.checkResponse(a,b)))return b;if(typeof a=="string")return this.fromString(a);return a},getRecords:function(a){return this.xpath(a,this.records)},records:"/*/item",userdata:"/*/userdata",getDetails:function(a){return this.tagToObject(a,{})},getUserData:function(a,b){b=b||{};var c=this.xpath(a,this.userdata);for(a=0;a<c.length;a++){var d=this.tagToObject(c[a]);b[d.name]=d.value}return b},getInfo:function(a){return{w:a.documentElement.getAttribute("total_count")||
|
||||
0,u:a.documentElement.getAttribute("pos")||0}},xpath:function(a,b){if(window.XPathResult){var c=a;if(a.nodeName.indexOf("document")==-1)a=a.ownerDocument;var d=[];a=a.evaluate(b,c,null,XPathResult.ANY_TYPE,null);for(b=a.iterateNext();b;){d.push(b);b=a.iterateNext()}return d}return a.selectNodes(b)},tagToObject:function(a,b){b=b||{};for(var c=a.attributes,d=0;d<c.length;d++)b[c[d].name]=c[d].value;var e=false,f=a.childNodes;for(d=0;d<f.length;d++)if(f[d].nodeType==1){var g=f[d].tagName;if(typeof b[g]!=
|
||||
"undefined"){b[g]instanceof Array||(b[g]=[b[g]]);b[g].push(this.tagToObject(f[d],{}))}else b[f[d].tagName]=this.tagToObject(f[d],{});e=true}if(!c.length&&!e)return this.nodeValue(a);b.value=this.nodeValue(a);return b},nodeValue:function(a){if(a.firstChild)return a.firstChild.data;return""},fromString:function(a){if(window.DOMParser)return(new DOMParser).parseFromString(a,"text/xml");if(window.ActiveXObject){temp=new ActiveXObject("Microsoft.xmlDOM");temp.loadXML(a);return temp}},checkResponse:function(a,
|
||||
b){if(b&&b.firstChild&&b.firstChild.tagName!="parsererror")return b;if(a=this.from_string(a.responseText.replace(/^[\s]+/,"")))return a}};dhtmlx.DataDriver.dhtmlxgrid={Ia:"_get_cell_value",toObject:function(a){return this.ea=a},getRecords:function(a){return a.rowsBuffer},getDetails:function(a){for(var b={},c=0;c<this.ea.getColumnsNum();c++)b["data"+c]=this.ea[this.Ia](a,c);return b},getInfo:function(){return{w:0,u:0}}};
|
||||
dhtmlx.Canvas={k:function(){this.D=[]},Ya:function(a){this.l=dhtmlx.html.create("canvas",{width:a.offsetWidth,height:a.offsetHeight});a.appendChild(this.l);if(!this.l.getContext)if(dhtmlx.r){dhtmlx.require("thirdparty/excanvas/excanvas.js");G_vmlCanvasManager.init_(document);G_vmlCanvasManager.initElement(this.l)}return this.l},getCanvas:function(a){return(this.l||this.Ya(this.g)).getContext(a||"2d")},$a:function(){if(this.l){this.l.setAttribute("width",this.l.parentNode.offsetWidth);this.l.setAttribute("height",
|
||||
this.l.parentNode.offsetHeight)}},renderText:function(a,b,c,d,e){if(c){a=dhtmlx.html.create("DIV",{"class":"dhx_canvas_text"+(d?" "+d:""),style:"left:"+a+"px; top:"+b+"px;"},c);this.g.appendChild(a);this.D.push(a);if(e)a.style.width=e+"px";return a}},renderTextAt:function(a,b,c,d,e,f,g){if(e=this.renderText.call(this,c,d,e,f,g)){if(a)e.style.top=a=="middle"?parseInt(d-e.offsetHeight/2,10)+"px":d-e.offsetHeight+"px";if(b)e.style.left=b=="left"?c-e.offsetWidth+"px":parseInt(c-e.offsetWidth/2,10)+"px"}return e},
|
||||
clearCanvas:function(){for(var a=0;a<this.D.length;a++)this.g.removeChild(this.D[a]);this.D=[];if(this.g.v){this.g.v.parentNode.removeChild(this.g.v);this.g.v=null}this.getCanvas().clearRect(0,0,this.l.offsetWidth,this.l.offsetHeight)}};
|
||||
dhtmlXChart=function(a){this.name="Chart";this.version="3.0";dhtmlx.extend(this,dhtmlx.Settings);this.Xa(a,"dhx_chart");dhtmlx.extend(this,dhtmlx.DataLoader);this.data.provideApi(this,true);dhtmlx.extend(this,dhtmlx.EventSystem);dhtmlx.extend(this,dhtmlx.MouseEvents);dhtmlx.extend(this,dhtmlx.Destruction);dhtmlx.extend(this,dhtmlx.Canvas);dhtmlx.extend(this,dhtmlx.Group);dhtmlx.extend(this,dhtmlx.AutoTooltip);for(var b in dhtmlx.chart)dhtmlx.extend(this,dhtmlx.chart[b]);this.B(a,{color:"RAINBOW",
|
||||
alpha:"1",label:false,value:"{obj.value}",padding:{},view:"pie",lineColor:"#ffffff",cant:0.5,width:15,labelWidth:100,line:{},item:{},shadow:true,gradient:false,border:true,labelOffset:20,origin:"auto"});this.h=[this.e];this.data.attachEvent("onStoreUpdated",dhtmlx.bind(function(){this.render()},this));this.attachEvent("onLocateData",this.db)};
|
||||
dhtmlXChart.prototype={q:"dhx_area_id",on_click:{},on_dblclick:{},on_mouse_move:{},resize:function(){this.$a();this.render()},view_setter:function(a,b){if(typeof this.e.offset=="undefined")this.e.offset=b=="area"||b=="stackedArea"?false:true;return b},render:function(){if(this.callEvent("onBeforeRender",[this.data])){this.clearCanvas();this.e.legend&&this.za(this.getCanvas(),this.data.getRange(),this.g.offsetWidth,this.g.offsetHeight);for(var a=this.Ea(this.g.offsetWidth,this.g.offsetHeight),b=new dhtmlx.ui.Map(this.q),
|
||||
c=this.e,d=0;d<this.h.length;d++){this.e=this.h[d];this["pvt_render_"+this.e.view](this.getCanvas(),this.data.getRange(),a.start,a.end,d,b)}b.render(this.g);this.e=c}},value_setter:dhtmlx.Template.obj_setter,alpha_setter:dhtmlx.Template.obj_setter,label_setter:dhtmlx.Template.obj_setter,lineColor_setter:dhtmlx.Template.obj_setter,pieInnerText_setter:dhtmlx.Template.obj_setter,gradient_setter:function(a,b){if(typeof b!="function"&&b&&(b===true||b!="3d"))b="light";return b},colormap:{RAINBOW:function(a){a=
|
||||
Math.floor(this.indexById(a.id)/this.dataCount()*1536);if(a==1536)a-=1;return this.Za[Math.floor(a/256)](a%256)}},color_setter:function(a,b){return this.colormap[b]||dhtmlx.Template.obj_setter(a,b)},legend_setter:function(a,b){if(typeof b!="object")b={template:b};this.n(b,{width:150,height:18,layout:"y",align:"left",valign:"bottom",template:"",marker:{type:"square",width:25,height:15}});b.template=dhtmlx.Template.setter(0,b.template);return b},item_setter:function(a,b){if(typeof b!="object")b={color:b,
|
||||
borderColor:b};this.n(b,{radius:4,color:"#000000",borderColor:"#000000",borderWidth:2});b.color=dhtmlx.Template.setter(0,b.color);b.borderColor=dhtmlx.Template.setter(0,b.borderColor);return b},line_setter:function(a,b){if(typeof b!="object")b={color:b};this.n(b,{width:3,color:"#d4d4d4"});b.color=dhtmlx.Template.setter(0,b.color);return b},padding_setter:function(a,b){if(typeof b!="object")b={left:b,right:b,top:b,bottom:b};this.n(b,{left:50,right:20,top:35,bottom:40});return b},xAxis_setter:function(a,
|
||||
b){if(!b)return false;if(typeof b!="object")b={template:b};this.n(b,{title:"",color:"#000000",template:"{obj}",lines:false});if(b.template)b.template=dhtmlx.Template.setter(0,b.template);return b},yAxis_setter:function(a,b){this.n(b,{title:"",color:"#000000",template:"{obj}",lines:true});if(b.template)b.template=dhtmlx.Template.setter(0,b.template);return b},N:function(a,b,c,d,e,f,g){e=this.Da(a,b,c,d,e,f);this.da(a,b,c,d,g,e);return e},da:function(a,b,c,d,e,f){if(this.e.xAxis){var g=c.x-0.5;f=parseInt(f?
|
||||
f:d.y,10)+0.5;var i=d.x,j,k=true;this.i(a,g,f,i,f,this.e.xAxis.color,1);for(var h=0;h<b.length;h++){if(this.e.offset===true)j=g+e/2+h*e;else{j=g+h*e;k=!!h}var m=this.e.origin!="auto"&&this.e.view=="bar"&&parseFloat(this.e.value(b[h]))<this.e.origin;this.Ba(j,f,b[h],k,m);this.e.view_setter!="bar"&&this.Ca(a,j,d.y,c.y)}this.renderTextAt(true,false,g,d.y+this.e.padding.bottom-3,this.e.xAxis.title,"dhx_axis_title_x",d.x-c.x);this.e.xAxis.lines&&this.e.offset&&this.i(a,i+0.5,d.y,i+0.5,c.y+0.5,this.e.xAxis.color,
|
||||
0.2)}},Da:function(a,b,c,d,e,f){var g;b={};if(this.e.yAxis){var i=c.x-0.5,j=d.y,k=c.y,h=d.y;this.i(a,i,j,i,k,this.e.yAxis.color,1);if(this.e.yAxis.step)g=parseFloat(this.e.yAxis.step);if(typeof this.e.yAxis.step=="undefined"||typeof this.e.yAxis.start=="undefined"||typeof this.e.yAxis.end=="undefined"){b=this.V(e,f);e=b.start;f=b.end;g=b.step;this.e.yAxis.end=f;this.e.yAxis.start=e}if(g!==0){k=(j-k)*g/(f-e);for(var m=0,l=e;l<=f;l+=g){if(b.fixNum)l=parseFloat((new Number(l)).toFixed(b.fixNum));var n=
|
||||
Math.floor(j-m*k)+0.5;!(l==e&&this.e.origin=="auto")&&this.e.yAxis.lines&&this.i(a,i,n,d.x,n,this.e.yAxis.color,0.2);if(l==this.e.origin)h=n;this.renderText(0,n-5,this.e.yAxis.template(l.toString()),"dhx_axis_item_y",c.x-5);m++}this.oa(c,d);return h}}},oa:function(a,b){if(a=this.renderTextAt("middle",false,0,parseInt((b.y-a.y)/2+a.y,10),this.e.yAxis.title,"dhx_axis_title_y"))a.style.left=(dhtmlx.env.transform?(a.offsetHeight-a.offsetWidth)/2:0)+"px"},V:function(a,b){if(this.e.origin!="auto"&&this.e.origin<
|
||||
a)a=this.e.origin;var c,d,e;c=(b-a)/8||1;var f=Math.floor(this.ga(c)),g=Math.pow(10,f),i=c/g;i=i>5?10:5;c=parseInt(i,10)*g;if(c>Math.abs(a))d=a<0?-c:0;else{var j=Math.abs(a),k=Math.floor(this.ga(j)),h=j/Math.pow(10,k);d=Math.ceil(h*10)/10*Math.pow(10,k)-c;if(a<0)d=-d-2*c}for(e=d;e<b;){e+=c;e=parseFloat((new Number(e)).toFixed(Math.abs(f)))}return{start:d,end:e,step:c,fixNum:Math.abs(f)}},O:function(a){var b,c;if((c=arguments.length&&a=="h"?this.e.xAxis:this.e.yAxis)&&typeof c.end!="undefied"&&typeof c.start!=
|
||||
"undefied"&&c.step){b=parseFloat(c.end);c=parseFloat(c.start)}else{b=this.max(this.h[0].value);c=this.min(this.h[0].value);if(this.h.length>1)for(var d=1;d<this.h.length;d++){var e=this.max(this.h[d].value),f=this.min(this.h[d].value);if(e>b)b=e;if(f<c)c=f}}return{max:b,min:c}},ga:function(a){var b="log";return Math.floor(Math[b](a)/Math.LN10)},Ba:function(a,b,c,d,e){this.e.xAxis&&this.renderTextAt(e,d,a,b,this.e.xAxis.template(c), "dhx_axis_item_x")},Ca:function(a,b,c,d){this.e.xAxis&&this.e.xAxis.lines&&this.i(a,
|
||||
b,c,b,d,this.e.xAxis.color,0.2)},i:function(a,b,c,d,e,f,g){a.strokeStyle=f;a.lineWidth=g;a.beginPath();a.moveTo(b,c);a.lineTo(d,e);a.stroke()},z:function(a,b){var c=1;if(b!=a){a=b-a;if(Math.abs(a)<1)for(;Math.abs(a)<1;){c*=10;a*=c}}else a=a;return[a,c]},Za:[function(a){return"#FF"+dhtmlx.math.toHex(a/2,2)+"00"},function(a){return"#FF"+dhtmlx.math.toHex(a/2+128,2)+"00"},function(a){return"#"+dhtmlx.math.toHex(255-a,2)+"FF00"},function(a){return"#00FF"+dhtmlx.math.toHex(a,2)},function(a){return"#00"+
|
||||
dhtmlx.math.toHex(255-a,2)+"FF"},function(a){return"#"+dhtmlx.math.toHex(a,2)+"00FF"}],addSeries:function(a){var b=this.e;this.e=dhtmlx.extend({},b);this.B(a,{});this.h.push(this.e);this.e=b},db:function(a,b){this.ra=b.getAttribute("userdata");for(a=0;a<this.h.length;a++){var c=this.h[a].tooltip;c&&c.disable()}(c=this.h[this.ra].tooltip)&&c.enable()},za:function(a,b){var c=0,d=0,e=this.e.legend,f,g,i=this.e.legend.layout!="x"?"width:"+e.width+"px":"",j=dhtmlx.html.create("DIV",{"class":"dhx_chart_legend",
|
||||
style:"left:"+c+"px; top:"+d+"px;"+i},"");this.g.appendChild(j);var k=[];if(e.values)for(h=0;h<e.values.length;h++)k.push(this.aa(j,e.values[h].text));else for(var h=0;h<b.length;h++)k.push(this.aa(j,e.template(b[h])));g=j.offsetWidth;f=j.offsetHeight;this.e.legend.width=g;this.e.legend.height=f;if(g<this.g.offsetWidth){if(e.layout=="x"&&e.align=="center")c=(this.g.offsetWidth-g)/2;if(e.align=="right")c=this.g.offsetWidth-g}if(f<this.g.offsetHeight)if(e.valign=="middle"&&e.align!="center"&&e.layout!=
|
||||
"x")d=(this.g.offsetHeight-f)/2;else if(e.valign=="bottom")d=this.g.offsetHeight-f;j.style.left=c+"px";j.style.top=d+"px";for(h=0;h<k.length;h++){var m=k[h],l=e.values?e.values[h].color:this.e.color.call(this,b[h]);this.Aa(a,m.offsetLeft+c,m.offsetTop+d,l)}k=null},aa:function(a,b){var c="";if(this.e.legend.layout=="x")c="float:left;";b=dhtmlx.html.create("DIV",{style:c+"padding-left:"+(10+this.e.legend.marker.width)+"px","class":"dhx_chart_legend_item"},b);a.appendChild(b);return b},Aa:function(a,
|
||||
b,c,d){var e=this.e.legend;a.strokeStyle=a.fillStyle=d;a.lineWidth=e.marker.height;a.lineCap=e.marker.type;a.beginPath();b+=a.lineWidth/2+5;c+=a.lineWidth/2+3;a.moveTo(b,c);b=b+e.marker.width-e.marker.height+1;a.lineTo(b,c);a.stroke()},Ea:function(a,b){var c,d,e,f;c=this.e.padding.left;d=this.e.padding.top;e=a-this.e.padding.right;f=b-this.e.padding.bottom;if(this.e.legend){a=this.e.legend;b=this.e.legend.width;var g=this.e.legend.height;if(a.layout=="x")if(a.valign=="center")if(a.align=="right")e-=
|
||||
b;else{if(a.align=="left")c+=b}else if(a.valign=="bottom")f-=g;else d+=g;else if(a.align=="right")e-=b;else if(a.align=="left")c+=b}return{start:{x:c,y:d},end:{x:e,y:f}}},Q:function(a){var b,c;if(this.e.yAxis&&typeof this.e.yAxis.end!="undefied"&&typeof this.e.yAxis.start!="undefied"&&this.e.yAxis.step){b=parseFloat(this.e.yAxis.end);c=parseFloat(this.e.yAxis.start)}else{for(var d=0;d<a.length;d++){a[d].$sum=0;a[d].$min=Infinity;for(b=0;b<this.h.length;b++){c=parseFloat(this.h[b].value(a[d]));if(!isNaN(c)){a[d].$sum+=
|
||||
c;if(c<a[d].$min)a[d].$min=c}}}b=-Infinity;c=Infinity;for(d=0;d<a.length;d++){if(a[d].$sum>b)b=a[d].$sum;if(a[d].$min<c)c=a[d].$min}if(c>0)c=0}return{max:b,min:c}},G:function(a,b,c,d,e,f,g,i){if(f=="light"){a=i=="x"?a.createLinearGradient(b,c,d,c):a.createLinearGradient(b,c,b,e);a.addColorStop(0,"#FFFFFF");a.addColorStop(0.9,g);a.addColorStop(1,g);g=2}else{a.globalAlpha=0.37;g=0;a=i=="x"?a.createLinearGradient(b,e,b,c):a.createLinearGradient(b,c,d,c);a.addColorStop(0,"#000000");a.addColorStop(0.5,
|
||||
"#FFFFFF");a.addColorStop(0.6,"#FFFFFF");a.addColorStop(1,"#000000")}return{gradient:a,offset:g}}};dhtmlx.compat("layout");
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
Copyright DHTMLX LTD. http://www.dhtmlx.com
|
||||
You allowed to use this component or parts of it under GPL terms
|
||||
To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
|
||||
*/
|
||||
/*pure colors*/
/*fonts*/
/*2010 September 28*//* DHX DEPEND FROM FILE 'tooltip.css'*//*style used by tooltip's container*/
.dhx_tooltip{
display:none;
position:absolute;
font-family:Tahoma;
font-size:8pt;
z-index:10000;
background-color:white;
padding:2px 2px 2px 2px;
border:1px solid #A4BED4;
}/* DHX DEPEND FROM FILE 'chart.css'*//*chart container*/
.dhx_chart{
position:relative;
font-family:Verdana;
font-size:13px;
color:#000000;
overflow:hidden;
}
/*labels*/
.dhx_canvas_text{
position:absolute;
text-align:center;
overflow:hidden;
white-space:nowrap;
}
/*map*/
.dhx_map_img{
width : 100%;
height : 100%;
position : absolute;
top : 0px;
left : 0px;
border:0px;
filter:alpha(opacity=0);
}
/*scales*/
.dhx_axis_item_y{
position:absolute;
height:10px;
line-height:10px;
text-align:right;
}
.dhx_axis_title_x{
text-align:center;
}
.dhx_axis_title_y{
text-align:center;
font-family:Verdana;
/*safari*/
-webkit-transform: rotate(-90deg);
/*firefox*/
-moz-transform: rotate(-90deg);
/*IE*/
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
/*opera*/
-o-transform:rotate(-90deg);
padding-left:3px;
}
/*legend block*/
.dhx_chart_legend{
position:absolute;
}
.dhx_chart_legend_item{
height:18px;
line-height:18px;
padding: 2px;
}
|
File diff suppressed because it is too large
Load Diff
10
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/AUTHORS
vendored
Normal file
10
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/AUTHORS
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
ExplorerCanvas
|
||||
|
||||
Google Open Source:
|
||||
<http://code.google.com>
|
||||
<opensource@google.com>
|
||||
|
||||
Developers:
|
||||
Emil A Eklund <emil@eae.net>
|
||||
Erik Arvidsson <erik@eae.net>
|
||||
Glen Murphy <glen@glenmurphy.com>
|
202
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/COPYING
vendored
Normal file
202
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/COPYING
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
22
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/README
vendored
Normal file
22
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/README
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
ExplorerCanvas
|
||||
Copyright 2006 Google Inc.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
DESCRIPTION
|
||||
|
||||
Firefox, Safari and Opera 9 support the canvas tag to allow 2D command-based
|
||||
drawing operations. ExplorerCanvas brings the same functionality to Internet
|
||||
Explorer; web developers only need to include a single script tag in their
|
||||
existing canvas webpages to enable this support.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
INSTALLATION
|
||||
|
||||
Include the ExplorerCanvas tag in the same directory as your HTML files, and
|
||||
add the following code to your page, preferably in the <head> tag.
|
||||
|
||||
<!--[if IE]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
|
||||
|
||||
If you run into trouble, please look at the included example code to see how
|
||||
to best implement this
|
927
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/excanvas.js
vendored
Normal file
927
addons/base_graph/static/lib/dhtmlxGraph/codebase/thirdparty/excanvas/excanvas.js
vendored
Normal file
|
@ -0,0 +1,927 @@
|
|||
// Copyright 2006 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
// Known Issues:
|
||||
//
|
||||
// * Patterns are not implemented.
|
||||
// * Radial gradient are not implemented. The VML version of these look very
|
||||
// different from the canvas one.
|
||||
// * Clipping paths are not implemented.
|
||||
// * Coordsize. The width and height attribute have higher priority than the
|
||||
// width and height style values which isn't correct.
|
||||
// * Painting mode isn't implemented.
|
||||
// * Canvas width/height should is using content-box by default. IE in
|
||||
// Quirks mode will draw the canvas using border-box. Either change your
|
||||
// doctype to HTML5
|
||||
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
|
||||
// or use Box Sizing Behavior from WebFX
|
||||
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
|
||||
// * Non uniform scaling does not correctly scale strokes.
|
||||
// * Optimize. There is always room for speed improvements.
|
||||
|
||||
// Only add this code if we do not already have a canvas implementation
|
||||
if (!document.createElement('canvas').getContext) {
|
||||
|
||||
(function() {
|
||||
|
||||
// alias some functions to make (compiled) code shorter
|
||||
var m = Math;
|
||||
var mr = m.round;
|
||||
var ms = m.sin;
|
||||
var mc = m.cos;
|
||||
var abs = m.abs;
|
||||
var sqrt = m.sqrt;
|
||||
|
||||
// this is used for sub pixel precision
|
||||
var Z = 10;
|
||||
var Z2 = Z / 2;
|
||||
|
||||
/**
|
||||
* This funtion is assigned to the <canvas> elements as element.getContext().
|
||||
* @this {HTMLElement}
|
||||
* @return {CanvasRenderingContext2D_}
|
||||
*/
|
||||
function getContext() {
|
||||
return this.context_ ||
|
||||
(this.context_ = new CanvasRenderingContext2D_(this));
|
||||
}
|
||||
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
/**
|
||||
* Binds a function to an object. The returned function will always use the
|
||||
* passed in {@code obj} as {@code this}.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* g = bind(f, obj, a, b)
|
||||
* g(c, d) // will do f.call(obj, a, b, c, d)
|
||||
*
|
||||
* @param {Function} f The function to bind the object to
|
||||
* @param {Object} obj The object that should act as this when the function
|
||||
* is called
|
||||
* @param {*} var_args Rest arguments that will be used as the initial
|
||||
* arguments when the function is called
|
||||
* @return {Function} A new function that has bound this
|
||||
*/
|
||||
function bind(f, obj, var_args) {
|
||||
var a = slice.call(arguments, 2);
|
||||
return function() {
|
||||
return f.apply(obj, a.concat(slice.call(arguments)));
|
||||
};
|
||||
}
|
||||
|
||||
var G_vmlCanvasManager_ = {
|
||||
init: function(opt_doc) {
|
||||
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
|
||||
var doc = opt_doc || document;
|
||||
// Create a dummy element so that IE will allow canvas elements to be
|
||||
// recognized.
|
||||
doc.createElement('canvas');
|
||||
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
|
||||
}
|
||||
},
|
||||
|
||||
init_: function(doc) {
|
||||
// create xmlns
|
||||
if (!doc.namespaces['g_vml_']) {
|
||||
doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
|
||||
'#default#VML');
|
||||
|
||||
}
|
||||
if (!doc.namespaces['g_o_']) {
|
||||
doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
|
||||
'#default#VML');
|
||||
}
|
||||
|
||||
// Setup default CSS. Only add one style sheet per document
|
||||
if (!doc.styleSheets['ex_canvas_']) {
|
||||
var ss = doc.createStyleSheet();
|
||||
ss.owningElement.id = 'ex_canvas_';
|
||||
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
|
||||
// default size is 300x150 in Gecko and Opera
|
||||
'text-align:left;width:300px;height:150px}' +
|
||||
'g_vml_\\:*{behavior:url(#default#VML)}' +
|
||||
'g_o_\\:*{behavior:url(#default#VML)}';
|
||||
|
||||
}
|
||||
|
||||
// find all canvas elements
|
||||
var els = doc.getElementsByTagName('canvas');
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
this.initElement(els[i]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Public initializes a canvas element so that it can be used as canvas
|
||||
* element from now on. This is called automatically before the page is
|
||||
* loaded but if you are creating elements using createElement you need to
|
||||
* make sure this is called on the element.
|
||||
* @param {HTMLElement} el The canvas element to initialize.
|
||||
* @return {HTMLElement} the element that was created.
|
||||
*/
|
||||
initElement: function(el) {
|
||||
if (!el.getContext) {
|
||||
|
||||
el.getContext = getContext;
|
||||
|
||||
// Remove fallback content. There is no way to hide text nodes so we
|
||||
// just remove all childNodes. We could hide all elements and remove
|
||||
// text nodes but who really cares about the fallback content.
|
||||
el.innerHTML = '';
|
||||
|
||||
// do not use inline function because that will leak memory
|
||||
el.attachEvent('onpropertychange', onPropertyChange);
|
||||
el.attachEvent('onresize', onResize);
|
||||
|
||||
var attrs = el.attributes;
|
||||
if (attrs.width && attrs.width.specified) {
|
||||
// TODO: use runtimeStyle and coordsize
|
||||
// el.getContext().setWidth_(attrs.width.nodeValue);
|
||||
el.style.width = attrs.width.nodeValue + 'px';
|
||||
} else {
|
||||
el.width = el.clientWidth;
|
||||
}
|
||||
if (attrs.height && attrs.height.specified) {
|
||||
// TODO: use runtimeStyle and coordsize
|
||||
// el.getContext().setHeight_(attrs.height.nodeValue);
|
||||
el.style.height = attrs.height.nodeValue + 'px';
|
||||
} else {
|
||||
el.height = el.clientHeight;
|
||||
}
|
||||
//el.getContext().setCoordsize_()
|
||||
}
|
||||
return el;
|
||||
}
|
||||
};
|
||||
|
||||
function onPropertyChange(e) {
|
||||
var el = e.srcElement;
|
||||
|
||||
switch (e.propertyName) {
|
||||
case 'width':
|
||||
el.style.width = el.attributes.width.nodeValue + 'px';
|
||||
el.getContext().clearRect();
|
||||
break;
|
||||
case 'height':
|
||||
el.style.height = el.attributes.height.nodeValue + 'px';
|
||||
el.getContext().clearRect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function onResize(e) {
|
||||
var el = e.srcElement;
|
||||
if (el.firstChild) {
|
||||
el.firstChild.style.width = el.clientWidth + 'px';
|
||||
el.firstChild.style.height = el.clientHeight + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
G_vmlCanvasManager_.init();
|
||||
|
||||
// precompute "00" to "FF"
|
||||
var dec2hex = [];
|
||||
for (var i = 0; i < 16; i++) {
|
||||
for (var j = 0; j < 16; j++) {
|
||||
dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
|
||||
}
|
||||
}
|
||||
|
||||
function createMatrixIdentity() {
|
||||
return [
|
||||
[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 1]
|
||||
];
|
||||
}
|
||||
|
||||
function matrixMultiply(m1, m2) {
|
||||
var result = createMatrixIdentity();
|
||||
|
||||
for (var x = 0; x < 3; x++) {
|
||||
for (var y = 0; y < 3; y++) {
|
||||
var sum = 0;
|
||||
|
||||
for (var z = 0; z < 3; z++) {
|
||||
sum += m1[x][z] * m2[z][y];
|
||||
}
|
||||
|
||||
result[x][y] = sum;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function copyState(o1, o2) {
|
||||
o2.fillStyle = o1.fillStyle;
|
||||
o2.lineCap = o1.lineCap;
|
||||
o2.lineJoin = o1.lineJoin;
|
||||
o2.lineWidth = o1.lineWidth;
|
||||
o2.miterLimit = o1.miterLimit;
|
||||
o2.shadowBlur = o1.shadowBlur;
|
||||
o2.shadowColor = o1.shadowColor;
|
||||
o2.shadowOffsetX = o1.shadowOffsetX;
|
||||
o2.shadowOffsetY = o1.shadowOffsetY;
|
||||
o2.strokeStyle = o1.strokeStyle;
|
||||
o2.globalAlpha = o1.globalAlpha;
|
||||
o2.arcScaleX_ = o1.arcScaleX_;
|
||||
o2.arcScaleY_ = o1.arcScaleY_;
|
||||
o2.lineScale_ = o1.lineScale_;
|
||||
}
|
||||
|
||||
function processStyle(styleString) {
|
||||
var str, alpha = 1;
|
||||
|
||||
styleString = String(styleString);
|
||||
if (styleString.substring(0, 3) == 'rgb') {
|
||||
var start = styleString.indexOf('(', 3);
|
||||
var end = styleString.indexOf(')', start + 1);
|
||||
var guts = styleString.substring(start + 1, end).split(',');
|
||||
|
||||
str = '#';
|
||||
for (var i = 0; i < 3; i++) {
|
||||
str += dec2hex[Number(guts[i])];
|
||||
}
|
||||
|
||||
if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
|
||||
alpha = guts[3];
|
||||
}
|
||||
} else {
|
||||
str = styleString;
|
||||
}
|
||||
|
||||
return {color: str, alpha: alpha};
|
||||
}
|
||||
|
||||
function processLineCap(lineCap) {
|
||||
switch (lineCap) {
|
||||
case 'butt':
|
||||
return 'flat';
|
||||
case 'round':
|
||||
return 'round';
|
||||
case 'square':
|
||||
default:
|
||||
return 'square';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class implements CanvasRenderingContext2D interface as described by
|
||||
* the WHATWG.
|
||||
* @param {HTMLElement} surfaceElement The element that the 2D context should
|
||||
* be associated with
|
||||
*/
|
||||
function CanvasRenderingContext2D_(surfaceElement) {
|
||||
this.m_ = createMatrixIdentity();
|
||||
|
||||
this.mStack_ = [];
|
||||
this.aStack_ = [];
|
||||
this.currentPath_ = [];
|
||||
|
||||
// Canvas context properties
|
||||
this.strokeStyle = '#000';
|
||||
this.fillStyle = '#000';
|
||||
|
||||
this.lineWidth = 1;
|
||||
this.lineJoin = 'miter';
|
||||
this.lineCap = 'butt';
|
||||
this.miterLimit = Z * 1;
|
||||
this.globalAlpha = 1;
|
||||
this.canvas = surfaceElement;
|
||||
|
||||
var el = surfaceElement.ownerDocument.createElement('div');
|
||||
el.style.width = surfaceElement.clientWidth + 'px';
|
||||
el.style.height = surfaceElement.clientHeight + 'px';
|
||||
el.style.overflow = 'hidden';
|
||||
el.style.position = 'absolute';
|
||||
surfaceElement.appendChild(el);
|
||||
|
||||
this.element_ = el;
|
||||
this.arcScaleX_ = 1;
|
||||
this.arcScaleY_ = 1;
|
||||
this.lineScale_ = 1;
|
||||
}
|
||||
|
||||
var contextPrototype = CanvasRenderingContext2D_.prototype;
|
||||
contextPrototype.clearRect = function() {
|
||||
this.element_.innerHTML = '';
|
||||
};
|
||||
|
||||
contextPrototype.beginPath = function() {
|
||||
// TODO: Branch current matrix so that save/restore has no effect
|
||||
// as per safari docs.
|
||||
this.currentPath_ = [];
|
||||
};
|
||||
|
||||
contextPrototype.moveTo = function(aX, aY) {
|
||||
var p = this.getCoords_(aX, aY);
|
||||
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
|
||||
this.currentX_ = p.x;
|
||||
this.currentY_ = p.y;
|
||||
};
|
||||
|
||||
contextPrototype.lineTo = function(aX, aY) {
|
||||
var p = this.getCoords_(aX, aY);
|
||||
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
|
||||
|
||||
this.currentX_ = p.x;
|
||||
this.currentY_ = p.y;
|
||||
};
|
||||
|
||||
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
|
||||
aCP2x, aCP2y,
|
||||
aX, aY) {
|
||||
var p = this.getCoords_(aX, aY);
|
||||
var cp1 = this.getCoords_(aCP1x, aCP1y);
|
||||
var cp2 = this.getCoords_(aCP2x, aCP2y);
|
||||
bezierCurveTo(this, cp1, cp2, p);
|
||||
};
|
||||
|
||||
// Helper function that takes the already fixed cordinates.
|
||||
function bezierCurveTo(self, cp1, cp2, p) {
|
||||
self.currentPath_.push({
|
||||
type: 'bezierCurveTo',
|
||||
cp1x: cp1.x,
|
||||
cp1y: cp1.y,
|
||||
cp2x: cp2.x,
|
||||
cp2y: cp2.y,
|
||||
x: p.x,
|
||||
y: p.y
|
||||
});
|
||||
self.currentX_ = p.x;
|
||||
self.currentY_ = p.y;
|
||||
}
|
||||
|
||||
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
|
||||
// the following is lifted almost directly from
|
||||
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
|
||||
|
||||
var cp = this.getCoords_(aCPx, aCPy);
|
||||
var p = this.getCoords_(aX, aY);
|
||||
|
||||
var cp1 = {
|
||||
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
|
||||
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
|
||||
};
|
||||
var cp2 = {
|
||||
x: cp1.x + (p.x - this.currentX_) / 3.0,
|
||||
y: cp1.y + (p.y - this.currentY_) / 3.0
|
||||
};
|
||||
|
||||
bezierCurveTo(this, cp1, cp2, p);
|
||||
};
|
||||
|
||||
contextPrototype.arc = function(aX, aY, aRadius,
|
||||
aStartAngle, aEndAngle, aClockwise) {
|
||||
aRadius *= Z;
|
||||
var arcType = aClockwise ? 'at' : 'wa';
|
||||
|
||||
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
|
||||
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
|
||||
|
||||
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
|
||||
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
|
||||
|
||||
// IE won't render arches drawn counter clockwise if xStart == xEnd.
|
||||
if (xStart == xEnd && !aClockwise) {
|
||||
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
|
||||
// that can be represented in binary
|
||||
}
|
||||
|
||||
var p = this.getCoords_(aX, aY);
|
||||
var pStart = this.getCoords_(xStart, yStart);
|
||||
var pEnd = this.getCoords_(xEnd, yEnd);
|
||||
|
||||
this.currentPath_.push({type: arcType,
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
radius: aRadius,
|
||||
xStart: pStart.x,
|
||||
yStart: pStart.y,
|
||||
xEnd: pEnd.x,
|
||||
yEnd: pEnd.y});
|
||||
|
||||
};
|
||||
|
||||
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
|
||||
this.moveTo(aX, aY);
|
||||
this.lineTo(aX + aWidth, aY);
|
||||
this.lineTo(aX + aWidth, aY + aHeight);
|
||||
this.lineTo(aX, aY + aHeight);
|
||||
this.closePath();
|
||||
};
|
||||
|
||||
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
|
||||
var oldPath = this.currentPath_;
|
||||
this.beginPath();
|
||||
|
||||
this.moveTo(aX, aY);
|
||||
this.lineTo(aX + aWidth, aY);
|
||||
this.lineTo(aX + aWidth, aY + aHeight);
|
||||
this.lineTo(aX, aY + aHeight);
|
||||
this.closePath();
|
||||
this.stroke();
|
||||
|
||||
this.currentPath_ = oldPath;
|
||||
};
|
||||
|
||||
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
|
||||
var oldPath = this.currentPath_;
|
||||
this.beginPath();
|
||||
|
||||
this.moveTo(aX, aY);
|
||||
this.lineTo(aX + aWidth, aY);
|
||||
this.lineTo(aX + aWidth, aY + aHeight);
|
||||
this.lineTo(aX, aY + aHeight);
|
||||
this.closePath();
|
||||
this.fill();
|
||||
|
||||
this.currentPath_ = oldPath;
|
||||
};
|
||||
|
||||
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
|
||||
var gradient = new CanvasGradient_('gradient');
|
||||
gradient.x0_ = aX0;
|
||||
gradient.y0_ = aY0;
|
||||
gradient.x1_ = aX1;
|
||||
gradient.y1_ = aY1;
|
||||
return gradient;
|
||||
};
|
||||
|
||||
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
|
||||
aX1, aY1, aR1) {
|
||||
var gradient = new CanvasGradient_('gradientradial');
|
||||
gradient.x0_ = aX0;
|
||||
gradient.y0_ = aY0;
|
||||
gradient.r0_ = aR0;
|
||||
gradient.x1_ = aX1;
|
||||
gradient.y1_ = aY1;
|
||||
gradient.r1_ = aR1;
|
||||
return gradient;
|
||||
};
|
||||
|
||||
contextPrototype.drawImage = function(image, var_args) {
|
||||
var dx, dy, dw, dh, sx, sy, sw, sh;
|
||||
|
||||
// to find the original width we overide the width and height
|
||||
var oldRuntimeWidth = image.runtimeStyle.width;
|
||||
var oldRuntimeHeight = image.runtimeStyle.height;
|
||||
image.runtimeStyle.width = 'auto';
|
||||
image.runtimeStyle.height = 'auto';
|
||||
|
||||
// get the original size
|
||||
var w = image.width;
|
||||
var h = image.height;
|
||||
|
||||
// and remove overides
|
||||
image.runtimeStyle.width = oldRuntimeWidth;
|
||||
image.runtimeStyle.height = oldRuntimeHeight;
|
||||
|
||||
if (arguments.length == 3) {
|
||||
dx = arguments[1];
|
||||
dy = arguments[2];
|
||||
sx = sy = 0;
|
||||
sw = dw = w;
|
||||
sh = dh = h;
|
||||
} else if (arguments.length == 5) {
|
||||
dx = arguments[1];
|
||||
dy = arguments[2];
|
||||
dw = arguments[3];
|
||||
dh = arguments[4];
|
||||
sx = sy = 0;
|
||||
sw = w;
|
||||
sh = h;
|
||||
} else if (arguments.length == 9) {
|
||||
sx = arguments[1];
|
||||
sy = arguments[2];
|
||||
sw = arguments[3];
|
||||
sh = arguments[4];
|
||||
dx = arguments[5];
|
||||
dy = arguments[6];
|
||||
dw = arguments[7];
|
||||
dh = arguments[8];
|
||||
} else {
|
||||
throw Error('Invalid number of arguments');
|
||||
}
|
||||
|
||||
var d = this.getCoords_(dx, dy);
|
||||
|
||||
var w2 = sw / 2;
|
||||
var h2 = sh / 2;
|
||||
|
||||
var vmlStr = [];
|
||||
|
||||
var W = 10;
|
||||
var H = 10;
|
||||
|
||||
// For some reason that I've now forgotten, using divs didn't work
|
||||
vmlStr.push(' <g_vml_:group',
|
||||
' coordsize="', Z * W, ',', Z * H, '"',
|
||||
' coordorigin="0,0"' ,
|
||||
' style="width:', W, 'px;height:', H, 'px;position:absolute;');
|
||||
|
||||
// If filters are necessary (rotation exists), create them
|
||||
// filters are bog-slow, so only create them if abbsolutely necessary
|
||||
// The following check doesn't account for skews (which don't exist
|
||||
// in the canvas spec (yet) anyway.
|
||||
|
||||
if (this.m_[0][0] != 1 || this.m_[0][1]) {
|
||||
var filter = [];
|
||||
|
||||
// Note the 12/21 reversal
|
||||
filter.push('M11=', this.m_[0][0], ',',
|
||||
'M12=', this.m_[1][0], ',',
|
||||
'M21=', this.m_[0][1], ',',
|
||||
'M22=', this.m_[1][1], ',',
|
||||
'Dx=', mr(d.x / Z), ',',
|
||||
'Dy=', mr(d.y / Z), '');
|
||||
|
||||
// Bounding box calculation (need to minimize displayed area so that
|
||||
// filters don't waste time on unused pixels.
|
||||
var max = d;
|
||||
var c2 = this.getCoords_(dx + dw, dy);
|
||||
var c3 = this.getCoords_(dx, dy + dh);
|
||||
var c4 = this.getCoords_(dx + dw, dy + dh);
|
||||
|
||||
max.x = m.max(max.x, c2.x, c3.x, c4.x);
|
||||
max.y = m.max(max.y, c2.y, c3.y, c4.y);
|
||||
|
||||
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
|
||||
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
|
||||
filter.join(''), ", sizingmethod='clip');")
|
||||
} else {
|
||||
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
|
||||
}
|
||||
|
||||
vmlStr.push(' ">' ,
|
||||
'<g_vml_:image src="', image.src, '"',
|
||||
' style="width:', Z * dw, 'px;',
|
||||
' height:', Z * dh, 'px;"',
|
||||
' cropleft="', sx / w, '"',
|
||||
' croptop="', sy / h, '"',
|
||||
' cropright="', (w - sx - sw) / w, '"',
|
||||
' cropbottom="', (h - sy - sh) / h, '"',
|
||||
' />',
|
||||
'</g_vml_:group>');
|
||||
|
||||
this.element_.insertAdjacentHTML('BeforeEnd',
|
||||
vmlStr.join(''));
|
||||
};
|
||||
|
||||
contextPrototype.stroke = function(aFill) {
|
||||
var lineStr = [];
|
||||
var lineOpen = false;
|
||||
var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
|
||||
var color = a.color;
|
||||
var opacity = a.alpha * this.globalAlpha;
|
||||
|
||||
var W = 10;
|
||||
var H = 10;
|
||||
|
||||
lineStr.push('<g_vml_:shape',
|
||||
' filled="', !!aFill, '"',
|
||||
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
|
||||
' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
|
||||
' stroked="', !aFill, '"',
|
||||
' path="');
|
||||
|
||||
var newSeq = false;
|
||||
var min = {x: null, y: null};
|
||||
var max = {x: null, y: null};
|
||||
|
||||
for (var i = 0; i < this.currentPath_.length; i++) {
|
||||
var p = this.currentPath_[i];
|
||||
var c;
|
||||
|
||||
switch (p.type) {
|
||||
case 'moveTo':
|
||||
c = p;
|
||||
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
|
||||
break;
|
||||
case 'lineTo':
|
||||
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
|
||||
break;
|
||||
case 'close':
|
||||
lineStr.push(' x ');
|
||||
p = null;
|
||||
break;
|
||||
case 'bezierCurveTo':
|
||||
lineStr.push(' c ',
|
||||
mr(p.cp1x), ',', mr(p.cp1y), ',',
|
||||
mr(p.cp2x), ',', mr(p.cp2y), ',',
|
||||
mr(p.x), ',', mr(p.y));
|
||||
break;
|
||||
case 'at':
|
||||
case 'wa':
|
||||
lineStr.push(' ', p.type, ' ',
|
||||
mr(p.x - this.arcScaleX_ * p.radius), ',',
|
||||
mr(p.y - this.arcScaleY_ * p.radius), ' ',
|
||||
mr(p.x + this.arcScaleX_ * p.radius), ',',
|
||||
mr(p.y + this.arcScaleY_ * p.radius), ' ',
|
||||
mr(p.xStart), ',', mr(p.yStart), ' ',
|
||||
mr(p.xEnd), ',', mr(p.yEnd));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Following is broken for curves due to
|
||||
// move to proper paths.
|
||||
|
||||
// Figure out dimensions so we can do gradient fills
|
||||
// properly
|
||||
if (p) {
|
||||
if (min.x == null || p.x < min.x) {
|
||||
min.x = p.x;
|
||||
}
|
||||
if (max.x == null || p.x > max.x) {
|
||||
max.x = p.x;
|
||||
}
|
||||
if (min.y == null || p.y < min.y) {
|
||||
min.y = p.y;
|
||||
}
|
||||
if (max.y == null || p.y > max.y) {
|
||||
max.y = p.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
lineStr.push(' ">');
|
||||
|
||||
if (!aFill) {
|
||||
var lineWidth = this.lineScale_ * this.lineWidth;
|
||||
|
||||
// VML cannot correctly render a line if the width is less than 1px.
|
||||
// In that case, we dilute the color to make the line look thinner.
|
||||
if (lineWidth < 1) {
|
||||
opacity *= lineWidth;
|
||||
}
|
||||
|
||||
lineStr.push(
|
||||
'<g_vml_:stroke',
|
||||
' opacity="', opacity, '"',
|
||||
' joinstyle="', this.lineJoin, '"',
|
||||
' miterlimit="', this.miterLimit, '"',
|
||||
' endcap="', processLineCap(this.lineCap), '"',
|
||||
' weight="', lineWidth, 'px"',
|
||||
' color="', color, '" />'
|
||||
);
|
||||
} else if (typeof this.fillStyle == 'object') {
|
||||
var fillStyle = this.fillStyle;
|
||||
var angle = 0;
|
||||
var focus = {x: 0, y: 0};
|
||||
|
||||
// additional offset
|
||||
var shift = 0;
|
||||
// scale factor for offset
|
||||
var expansion = 1;
|
||||
|
||||
if (fillStyle.type_ == 'gradient') {
|
||||
var x0 = fillStyle.x0_ / this.arcScaleX_;
|
||||
var y0 = fillStyle.y0_ / this.arcScaleY_;
|
||||
var x1 = fillStyle.x1_ / this.arcScaleX_;
|
||||
var y1 = fillStyle.y1_ / this.arcScaleY_;
|
||||
var p0 = this.getCoords_(x0, y0);
|
||||
var p1 = this.getCoords_(x1, y1);
|
||||
var dx = p1.x - p0.x;
|
||||
var dy = p1.y - p0.y;
|
||||
angle = Math.atan2(dx, dy) * 180 / Math.PI;
|
||||
|
||||
// The angle should be a non-negative number.
|
||||
if (angle < 0) {
|
||||
angle += 360;
|
||||
}
|
||||
|
||||
// Very small angles produce an unexpected result because they are
|
||||
// converted to a scientific notation string.
|
||||
if (angle < 1e-6) {
|
||||
angle = 0;
|
||||
}
|
||||
} else {
|
||||
var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
|
||||
var width = max.x - min.x;
|
||||
var height = max.y - min.y;
|
||||
focus = {
|
||||
x: (p0.x - min.x) / width,
|
||||
y: (p0.y - min.y) / height
|
||||
};
|
||||
|
||||
width /= this.arcScaleX_ * Z;
|
||||
height /= this.arcScaleY_ * Z;
|
||||
var dimension = m.max(width, height);
|
||||
shift = 2 * fillStyle.r0_ / dimension;
|
||||
expansion = 2 * fillStyle.r1_ / dimension - shift;
|
||||
}
|
||||
|
||||
// We need to sort the color stops in ascending order by offset,
|
||||
// otherwise IE won't interpret it correctly.
|
||||
var stops = fillStyle.colors_;
|
||||
stops.sort(function(cs1, cs2) {
|
||||
return cs1.offset - cs2.offset;
|
||||
});
|
||||
|
||||
var length = stops.length;
|
||||
var color1 = stops[0].color;
|
||||
var color2 = stops[length - 1].color;
|
||||
var opacity1 = stops[0].alpha * this.globalAlpha;
|
||||
var opacity2 = stops[length - 1].alpha * this.globalAlpha;
|
||||
|
||||
var colors = [];
|
||||
for (var i = 0; i < length; i++) {
|
||||
var stop = stops[i];
|
||||
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
|
||||
}
|
||||
|
||||
// When colors attribute is used, the meanings of opacity and o:opacity2
|
||||
// are reversed.
|
||||
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
|
||||
' method="none" focus="100%"',
|
||||
' color="', color1, '"',
|
||||
' color2="', color2, '"',
|
||||
' colors="', colors.join(','), '"',
|
||||
' opacity="', opacity2, '"',
|
||||
' g_o_:opacity2="', opacity1, '"',
|
||||
' angle="', angle, '"',
|
||||
' focusposition="', focus.x, ',', focus.y, '" />');
|
||||
} else {
|
||||
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
|
||||
'" />');
|
||||
}
|
||||
|
||||
lineStr.push('</g_vml_:shape>');
|
||||
|
||||
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
|
||||
};
|
||||
|
||||
contextPrototype.fill = function() {
|
||||
this.stroke(true);
|
||||
}
|
||||
|
||||
contextPrototype.closePath = function() {
|
||||
this.currentPath_.push({type: 'close'});
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
contextPrototype.getCoords_ = function(aX, aY) {
|
||||
var m = this.m_;
|
||||
return {
|
||||
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
|
||||
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
|
||||
}
|
||||
};
|
||||
|
||||
contextPrototype.save = function() {
|
||||
var o = {};
|
||||
copyState(this, o);
|
||||
this.aStack_.push(o);
|
||||
this.mStack_.push(this.m_);
|
||||
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
|
||||
};
|
||||
|
||||
contextPrototype.restore = function() {
|
||||
copyState(this.aStack_.pop(), this);
|
||||
this.m_ = this.mStack_.pop();
|
||||
};
|
||||
|
||||
function matrixIsFinite(m) {
|
||||
for (var j = 0; j < 3; j++) {
|
||||
for (var k = 0; k < 2; k++) {
|
||||
if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function setM(ctx, m, updateLineScale) {
|
||||
if (!matrixIsFinite(m)) {
|
||||
return;
|
||||
}
|
||||
ctx.m_ = m;
|
||||
|
||||
if (updateLineScale) {
|
||||
// Get the line scale.
|
||||
// Determinant of this.m_ means how much the area is enlarged by the
|
||||
// transformation. So its square root can be used as a scale factor
|
||||
// for width.
|
||||
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
|
||||
ctx.lineScale_ = sqrt(abs(det));
|
||||
}
|
||||
}
|
||||
|
||||
contextPrototype.translate = function(aX, aY) {
|
||||
var m1 = [
|
||||
[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[aX, aY, 1]
|
||||
];
|
||||
|
||||
setM(this, matrixMultiply(m1, this.m_), false);
|
||||
};
|
||||
|
||||
contextPrototype.rotate = function(aRot) {
|
||||
var c = mc(aRot);
|
||||
var s = ms(aRot);
|
||||
|
||||
var m1 = [
|
||||
[c, s, 0],
|
||||
[-s, c, 0],
|
||||
[0, 0, 1]
|
||||
];
|
||||
|
||||
setM(this, matrixMultiply(m1, this.m_), false);
|
||||
};
|
||||
|
||||
contextPrototype.scale = function(aX, aY) {
|
||||
this.arcScaleX_ *= aX;
|
||||
this.arcScaleY_ *= aY;
|
||||
var m1 = [
|
||||
[aX, 0, 0],
|
||||
[0, aY, 0],
|
||||
[0, 0, 1]
|
||||
];
|
||||
|
||||
setM(this, matrixMultiply(m1, this.m_), true);
|
||||
};
|
||||
|
||||
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
|
||||
var m1 = [
|
||||
[m11, m12, 0],
|
||||
[m21, m22, 0],
|
||||
[dx, dy, 1]
|
||||
];
|
||||
|
||||
setM(this, matrixMultiply(m1, this.m_), true);
|
||||
};
|
||||
|
||||
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
|
||||
var m = [
|
||||
[m11, m12, 0],
|
||||
[m21, m22, 0],
|
||||
[dx, dy, 1]
|
||||
];
|
||||
|
||||
setM(this, m, true);
|
||||
};
|
||||
|
||||
/******** STUBS ********/
|
||||
contextPrototype.clip = function() {
|
||||
// TODO: Implement
|
||||
};
|
||||
|
||||
contextPrototype.arcTo = function() {
|
||||
// TODO: Implement
|
||||
};
|
||||
|
||||
contextPrototype.createPattern = function() {
|
||||
return new CanvasPattern_;
|
||||
};
|
||||
|
||||
// Gradient / Pattern Stubs
|
||||
function CanvasGradient_(aType) {
|
||||
this.type_ = aType;
|
||||
this.x0_ = 0;
|
||||
this.y0_ = 0;
|
||||
this.r0_ = 0;
|
||||
this.x1_ = 0;
|
||||
this.y1_ = 0;
|
||||
this.r1_ = 0;
|
||||
this.colors_ = [];
|
||||
}
|
||||
|
||||
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
|
||||
aColor = processStyle(aColor);
|
||||
this.colors_.push({offset: aOffset,
|
||||
color: aColor.color,
|
||||
alpha: aColor.alpha});
|
||||
};
|
||||
|
||||
function CanvasPattern_() {}
|
||||
|
||||
// set up externs
|
||||
G_vmlCanvasManager = G_vmlCanvasManager_;
|
||||
CanvasRenderingContext2D = CanvasRenderingContext2D_;
|
||||
CanvasGradient = CanvasGradient_;
|
||||
CanvasPattern = CanvasPattern_;
|
||||
|
||||
})();
|
||||
|
||||
} // if
|
||||
|
||||
if (dhtmlx && dhtmlx._modules)
|
||||
dhtmlx._modules["thirdparty/excanvas/excanvas.js"] = true;
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
dhtmlxChart v.2.6 Standard edition build 100928
|
||||
|
||||
This component is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. PLease contact sales@dhtmlx.com for details
|
||||
|
||||
|
||||
(c) DHTMLX Ltd.
|
|
@ -0,0 +1,70 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Data Loading: XML</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var barChart;
|
||||
window.onload=function(){
|
||||
barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:document.getElementById("chart_container"),
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
width:30,
|
||||
gradient:true,
|
||||
border:false
|
||||
})
|
||||
barChart.load("../common/sales.xml");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container2",
|
||||
value:"#sales#",
|
||||
details:"#year#"
|
||||
});
|
||||
barChart2.load("../common/sales.xml");
|
||||
}
|
||||
function reloada(){
|
||||
|
||||
barChart.destructor();
|
||||
barChart = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
details:"#year#"
|
||||
})
|
||||
barChart.load("../common/sales.xml");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Chart data can be loaded from different sources: xml,json,JS array,csv<br/> This samples demonstrates loading from xml file.</p>
|
||||
<div id="chart_container" style="width:450px;height:300px;border:1px solid #A4BED4;float:left;margin-right:20px"></div>
|
||||
<div id="chart_container2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
|
||||
<input type="button" name="some_name" value="reload" onclick="reloada()">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,63 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Data Loading: JSON</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ value:"2.9", label:"2000" },
|
||||
{ value:"3.5", label:"2001" },
|
||||
{ value:"3.1", label:"2002" },
|
||||
{ value:"4.2", label:"2003" },
|
||||
{ value:"4.5", label:"2004" },
|
||||
{ value:"9.6", label:"2005" },
|
||||
{ value:"7.4", label:"2006" },
|
||||
{ value:"9.0", label:"2007" },
|
||||
{ value:"7.3", label:"2008" },
|
||||
{ value:"2.8", label:"2009" }
|
||||
];
|
||||
window.onload = function(){
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
label:"#label#",
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
width:30,
|
||||
gradient:true,
|
||||
border:false
|
||||
})
|
||||
barChart.parse(data,"json");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container2",
|
||||
details:"#label#"
|
||||
});
|
||||
barChart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chart_container" style="width:450px;height:300px;border:1px solid #A4BED4;float:left;margin-right:20px"></div>
|
||||
<div id="chart_container2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Data Loading: CSV</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = "\
|
||||
2.9, 2000\n\
|
||||
3.5, 2001\n\
|
||||
3.1, 2002\n\
|
||||
4.2, 2003\n\
|
||||
4.5, 2004\n\
|
||||
9.6, 2005\n\
|
||||
7.4, 2006\n\
|
||||
9.0, 2007\n\
|
||||
7.3, 2008\n\
|
||||
2.8, 2009";
|
||||
window.onload = function(){
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#data0#",
|
||||
label:"#data1#",
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
width:30,
|
||||
gradient:true,
|
||||
border:false
|
||||
})
|
||||
barChart.parse(data,"csv");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container2",
|
||||
value:"#data0#",
|
||||
details:"#data1#"
|
||||
});
|
||||
barChart2.parse(data,"csv");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>When data are loaded from CSV string, you should use "data" and field index to define field in the template, for example, "#data0#","#data1#",etc.<br/>Charts in this sample represents values in the first column. Therefore, we have set value:"#data0#" in a chart contructor.</p>
|
||||
<div id="chart_container" style="width:450px;height:300px;border:1px solid #A4BED4;float:left;margin-right:20px"></div>
|
||||
<div id="chart_container2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,68 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Data Loading: JS array</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
[ "2.9", "2000" ],
|
||||
[ "3.5", "2001" ],
|
||||
[ "3.1", "2002" ],
|
||||
[ "4.2", "2003" ],
|
||||
[ "4.5", "2004" ],
|
||||
[ "9.6", "2005" ],
|
||||
[ "7.4", "2006" ],
|
||||
[ "9.0", "2007" ],
|
||||
[ "7.3", "2008" ],
|
||||
[ "2.8", "2009" ]
|
||||
];
|
||||
window.onload = function(){
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#data0#",
|
||||
label:"#data1#",
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
width:30,
|
||||
gradient:true,
|
||||
border:false
|
||||
})
|
||||
barChart.parse(data,"jsarray");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container2",
|
||||
value:"#data0#",
|
||||
details:"#data1#"
|
||||
});
|
||||
barChart2.parse(data,"jsarray");
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>When data are loaded from JS array, you should use "data" and field index to define field in the template, for example, "#data0#","#data1#",etc.<br/>Charts in this sample represents values in the first column. Therefore, we have set value:"#data0#" in a chart contructor.</p>
|
||||
<div id="chart_container" style="width:450px;height:300px;border:1px solid #A4BED4;float:left;margin-right:20px"></div>
|
||||
<div id="chart_container2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,119 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>PieChart: Initiazation</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
</head>
|
||||
<body >
|
||||
<h1>BarChart: Scales</h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Automatic vertical scale</td>
|
||||
<td>Custom vertical scale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:350px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0",sales1:"3.4",sales2:"1.2",sales3:"6.9", year:"2000" },
|
||||
{ sales:"3.8",sales1:"4.5",sales2:"2.5",sales3:"7.5", year:"2001" },
|
||||
{ sales:"3.4",sales1:"4.7",sales2:"1.9",sales3:"5.5", year:"2002" }
|
||||
];
|
||||
|
||||
|
||||
|
||||
var barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:30,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
title:"Sales,million"
|
||||
},
|
||||
gradient:true,
|
||||
border:false,
|
||||
color: "#66cc33"
|
||||
})
|
||||
barChart1.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#ff9933",
|
||||
label:"#sales1#"
|
||||
});
|
||||
barChart1.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#ffff99",
|
||||
label:"#sales2#"
|
||||
});
|
||||
barChart1.parse(data,"json");
|
||||
|
||||
|
||||
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:30,
|
||||
color: "#66cc33",
|
||||
label:"#sales#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Years",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start: 0,
|
||||
end: 10,
|
||||
step: 1,
|
||||
title:"Sales, mil"
|
||||
}
|
||||
|
||||
});
|
||||
barChart2.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#ff9933",
|
||||
label:"#sales1#"
|
||||
});
|
||||
barChart2.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#ffff99",
|
||||
label:"#sales2#"
|
||||
});
|
||||
barChart2.addSeries({
|
||||
value:"#sales3#",
|
||||
color:"#ccff99",
|
||||
label:"#sales3#"
|
||||
});
|
||||
|
||||
barChart2.parse(data,"json");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,66 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Colors: default</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"2.9", year:"2000" },
|
||||
{ sales:"3.5", year:"2001" },
|
||||
{ sales:"3.1", year:"2002" },
|
||||
{ sales:"4.2", year:"2003" },
|
||||
{ sales:"4.5", year:"2004" },
|
||||
{ sales:"9.6", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
window.onload = function(){
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
width:30
|
||||
})
|
||||
barChart.parse(data,"json");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container2",
|
||||
value:"#sales#",
|
||||
details:"#year#"
|
||||
});
|
||||
barChart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Chart colors are defined by color property. If it is not set, chart is colored using "rainbow" algorithm.</p>
|
||||
<div id="chart_container" style="width:450px;height:300px;border:1px solid #A4BED4;float:left;margin-right:20px"></div>
|
||||
<div id="chart_container2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,67 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Colors: custom colors</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"2.9", year:"2000", color:"#0000FF" },
|
||||
{ sales:"3.5", year:"2001", color:"#00FF00"},
|
||||
{ sales:"3.1", year:"2002", color:"#00FFFF"},
|
||||
{ sales:"4.2", year:"2003", color:"#FF0000"},
|
||||
{ sales:"4.5", year:"2004", color:"#FF00FF"},
|
||||
{ sales:"9.6", year:"2005", color:"#FFFF00"},
|
||||
{ sales:"7.4", year:"2006", color:"#880088"},
|
||||
{ sales:"9.0", year:"2007", color:"#008800"},
|
||||
{ sales:"7.3", year:"2008", color:"#880000"},
|
||||
{ sales:"4.8", year:"2009", color:"#000088"}
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
color:"#color#",
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
width:30
|
||||
})
|
||||
barChart.parse(data,"json");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container2",
|
||||
value:"#sales#",
|
||||
details:"#year#",
|
||||
color:"#color#"
|
||||
});
|
||||
barChart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Colors can be defined with template. In this sample colors and defined in data by "color" field.</p>
|
||||
<div id="chart_container" style="width:450px;height:300px;border:1px solid #A4BED4;float:left;margin-right:20px"></div>
|
||||
<div id="chart_container2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,77 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Colors: custom logic</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"2.9", year:"2000" },
|
||||
{ sales:"3.5", year:"2001" },
|
||||
{ sales:"3.1", year:"2002" },
|
||||
{ sales:"4.2", year:"2003" },
|
||||
{ sales:"4.5", year:"2004" },
|
||||
{ sales:"9.6", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
window.onload = function(){
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
width:30,
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
gradient:true,
|
||||
border:false,
|
||||
color:function(obj){
|
||||
if (obj.sales > 5) return "#FF0000";
|
||||
else return "#00FF00";
|
||||
}
|
||||
})
|
||||
barChart.parse(data,"json");
|
||||
|
||||
var index = 1;
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart_container2",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
gradient:true,
|
||||
color:function(obj,ratio){
|
||||
index++;
|
||||
if (index % 2) return "#FF0000";
|
||||
return "#00FF00";
|
||||
}
|
||||
});
|
||||
barChart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Colors can be defined using function. In this sample color of bars depends on sales value, and colors of pie sectors are alternative.</p>
|
||||
<div id="chart_container" style="width:450px;height:300px;border:1px solid #A4BED4;float:left;margin-right:20px""></div>
|
||||
<div id="chart_container2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,64 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Colors: color gradient</title>
|
||||
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"2.9", year:"2000" },
|
||||
{ sales:"3.5", year:"2001" },
|
||||
{ sales:"3.1", year:"2002" },
|
||||
{ sales:"4.2", year:"2003" },
|
||||
{ sales:"4.5", year:"2004" },
|
||||
{ sales:"9.6", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:0,
|
||||
left:0
|
||||
},
|
||||
width:30,
|
||||
gradient:function(gradient){
|
||||
gradient.addColorStop(1.0,"#FF0000");
|
||||
gradient.addColorStop(0.2,"#FFFF00");
|
||||
gradient.addColorStop(0.0,"#00FF22");
|
||||
}
|
||||
})
|
||||
barChart.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>The color of Bar Chart can be defined by gradient property. <br/>
|
||||
In this case you should set a function that takes a gradient object as an argument. And using addColorStop you may define colors for chart.</p>
|
||||
<div id="chart_container" style="width:500px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,96 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Grouping and Sorting</title>
|
||||
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var barChart;
|
||||
window.onload = function(){
|
||||
barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
color:"#b3e025",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:70,
|
||||
label:"#id#",
|
||||
sort:{
|
||||
by:"#id#",
|
||||
as:"string",
|
||||
dir:"asc"
|
||||
},
|
||||
group:{
|
||||
by:"#year#",
|
||||
map:{
|
||||
sales:["#sales#","sum"]
|
||||
}
|
||||
},
|
||||
padding:{
|
||||
bottom:0
|
||||
}
|
||||
})
|
||||
barChart.load("../common/stat.xml");
|
||||
}
|
||||
|
||||
function groupA(){
|
||||
barChart.group({
|
||||
by:"#company#",
|
||||
map:{
|
||||
sales:["#sales#","sum"]
|
||||
}
|
||||
});
|
||||
barChart.refresh();
|
||||
}
|
||||
|
||||
function groupB(){
|
||||
barChart.group({
|
||||
by:"#year#",
|
||||
map:{
|
||||
sales:["#sales#","sum"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function groupC(){
|
||||
barChart.group({
|
||||
by:"#year#",
|
||||
map:{
|
||||
sales:["#sales#","max"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>It's possible to group chart data by a certain property. You may use group method or group property in a chart constructor.</p>
|
||||
<div id="chart_container" style="width:600px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
|
||||
|
||||
<br/>
|
||||
<input type="button" name="some_name" value="Group by" onclick="window['group'+document.getElementById('groupby').value]()">
|
||||
<select name="groupby" id="groupby">
|
||||
<option value="A">company</option>
|
||||
<option value="B" SELECTED>year (total sales)</option>
|
||||
<option value="C">year (max sales)</option>
|
||||
</select>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,126 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Scales and grouping</title>
|
||||
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
<style>
|
||||
.dhx_chart_title{
|
||||
padding-left:3px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var barChart;
|
||||
window.onload = function(){
|
||||
barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
color:"#b3e025",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:70,
|
||||
yAxis:{},
|
||||
xAxis:{
|
||||
template:"#id#",
|
||||
title:"Sales per year (all companies)"
|
||||
},
|
||||
label:"#sales#",
|
||||
sort:{
|
||||
by:"#id#",
|
||||
as:"string",
|
||||
dir:"asc"
|
||||
},
|
||||
group:{
|
||||
by:"#year#",
|
||||
map:{
|
||||
sales:["#sales#","sum"]
|
||||
}
|
||||
}
|
||||
})
|
||||
barChart.load("../common/stat.xml");
|
||||
}
|
||||
|
||||
function groupA(){
|
||||
barChart.define("xAxis",{
|
||||
template:"#id#",
|
||||
title:"Total sales per companies"
|
||||
});
|
||||
barChart.define("yAxis",{});
|
||||
barChart.group({
|
||||
by:"#company#",
|
||||
map:{
|
||||
sales:["#sales#","sum"]
|
||||
}
|
||||
});
|
||||
barChart.refresh();
|
||||
}
|
||||
|
||||
function groupB(){
|
||||
barChart.define("xAxis",{
|
||||
template:"#id#",
|
||||
title:"Sales per year (all companies)"
|
||||
});
|
||||
barChart.define("yAxis",{});
|
||||
barChart.group({
|
||||
by:"#year#",
|
||||
map:{
|
||||
sales:["#sales#","sum"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function groupC(){
|
||||
barChart.define("xAxis",{
|
||||
template:"#id#",
|
||||
title:"Maximum sales per year"
|
||||
});
|
||||
barChart.define("yAxis",{});
|
||||
barChart.group({
|
||||
by:"#year#",
|
||||
map:{
|
||||
sales:["#sales#","max"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sort(direction){
|
||||
|
||||
barChart.define("sort",{
|
||||
by:"#sales#",
|
||||
dir:direction,
|
||||
as:"int"
|
||||
});
|
||||
barChart.render();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>To update configuration properties after grouping you need to cal define method with new settings.</p>
|
||||
<div id="chart_container" style="width:600px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
<br/>
|
||||
<input type="button" name="some_name" value="Group by" onclick="window['group'+document.getElementById('groupby').value]()">
|
||||
<select name="groupby" id="groupby">
|
||||
<option value="A">company</option>
|
||||
<option value="B" SELECTED>year (total sales)</option>
|
||||
<option value="C">year (max sales)</option>
|
||||
</select>
|
||||
<br/><br/>
|
||||
<input type="button" name="some_name" value="Sort by sales" onclick="sort(document.getElementById('dir').value)">
|
||||
<select name="dir" id="dir">
|
||||
<option value="asc" selected>asc</option>
|
||||
<option value="desc" >desc</option>
|
||||
</select>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,67 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Initialization</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"6300", company:"Company 1",color:"#d2ed7e" },
|
||||
{ sales:"8700", company:"Company 2",color:"#b3e025" },
|
||||
{ sales:"10500", company:"Company 3",color:"#9ac86d" },
|
||||
{ sales:"7800", company:"Company 4",color:"#e0e56c" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
color:"#color#",
|
||||
label:"#company#",
|
||||
pieInnerText:"<b>#sales#</b>",
|
||||
gradient:true
|
||||
});
|
||||
chart.parse(data,"json");
|
||||
|
||||
|
||||
var chart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
color:"#color#",
|
||||
label:"#company#",
|
||||
pieInnerText:"<b>#sales#</b>",
|
||||
gradient:true,
|
||||
radius:90,
|
||||
x:280,
|
||||
y:150
|
||||
});
|
||||
chart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<table>
|
||||
<tr>
|
||||
<td>Pie chart with Automatic radius and center position</td>
|
||||
<td>Pie chart with Custom radius and center position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,52 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Labels</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"10.7", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var pieChart = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
pieInnerText:"#sales#",
|
||||
label:"#year#"
|
||||
});
|
||||
pieChart.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<p>There are two properties to define sectors labels:
|
||||
<li>label - defines text outside sectors</li>
|
||||
<li>pieInnerText - set text inside sectors</li>
|
||||
</p>
|
||||
|
||||
<div id="chart" style="width:450px;height:300px;"></div></td>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,48 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>3D view</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"10.5", component:"dhxGrid",color:"#c7e1f3" },
|
||||
{ sales:"8.7", component:"dhxScheduler",color:"#45abf5" },
|
||||
{ sales:"6.3", component:"dhxTree",color:"#3590d0" },
|
||||
{ sales:"5.3", component:"dhxTabbar",color:"#BDDBF9" },
|
||||
{ sales:"4.5", component:"dhxLayout",color:"#d9e5ed" },
|
||||
{ sales:"4.2", component:"dhxMenu",color:"#aed7f4" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart = new dhtmlXChart({
|
||||
view:"pie3D",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
label:function(obj){
|
||||
var sum = chart.sum("#sales#");
|
||||
return obj.component+" ("+Math.round(parseFloat(obj.sales)/sum*100)+"%)";
|
||||
},
|
||||
color:"#color#",
|
||||
radius:110
|
||||
});
|
||||
chart.parse(data,"json");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chart" style="width:500px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,81 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Details Block</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
window.onload = function(){
|
||||
var pieChart = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
pieInnerText:"#sales#",
|
||||
gradient:true,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
legend:"#year#"
|
||||
});
|
||||
pieChart.parse(data,"json");
|
||||
|
||||
|
||||
var pieChart2 = new dhtmlXChart({
|
||||
view:"pie",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
pieInnerText:"#sales#",
|
||||
gradient:true,
|
||||
legend:{
|
||||
width: 75,
|
||||
align:"right",
|
||||
valign:"middle",
|
||||
marker:{
|
||||
type:"round",
|
||||
width:15
|
||||
},
|
||||
template:"#year#"
|
||||
}
|
||||
});
|
||||
pieChart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Pie Chart provides property "details" that displayes informationa about all sectors in a separate block.</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>PieChart with default details block</td>
|
||||
<td>PieChart with custom details block</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Initialization</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
item:{
|
||||
borderColor: "#ffffff",
|
||||
color: "#000000"
|
||||
},
|
||||
line:{
|
||||
color:"#ff9900",
|
||||
width:3
|
||||
}
|
||||
})
|
||||
chart.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chart" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Style definition</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
window.onload = function(){
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
var chart1 = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
item:{
|
||||
borderColor: "#ffffff",
|
||||
color: "#000000"
|
||||
},
|
||||
line:{
|
||||
color:"#ff9900",
|
||||
width:3
|
||||
}
|
||||
})
|
||||
chart1.parse(data,"json");
|
||||
|
||||
var chart2 = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
item:{
|
||||
borderColor: "#3399ff",
|
||||
color: "#ffffff"
|
||||
},
|
||||
line:{
|
||||
color:"#3399ff",
|
||||
width:3
|
||||
}
|
||||
})
|
||||
chart2.parse(data,"json");
|
||||
|
||||
var data2 = [
|
||||
{ sales:"1.2", year:"2000" },
|
||||
{ sales:"2.4", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"5.9", year:"2005" },
|
||||
{ sales:"6.5", year:"2006" },
|
||||
{ sales:"6.1", year:"2007" },
|
||||
{ sales:"6.0", year:"2008" },
|
||||
{ sales:"6.2", year:"2009" }
|
||||
];
|
||||
var chart3 = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart3",
|
||||
value:"#sales#",
|
||||
item:{
|
||||
radius:0
|
||||
},
|
||||
line:{
|
||||
color:"#b25151",
|
||||
width:3
|
||||
},
|
||||
xAxis:{
|
||||
title:"Years",
|
||||
template:"#year#",
|
||||
lines:true
|
||||
},
|
||||
yAxis:{
|
||||
start: 0,
|
||||
end: 10,
|
||||
step: 1,
|
||||
title:"Sales, mil"
|
||||
},
|
||||
tooltip:{
|
||||
template:"#year#"
|
||||
}
|
||||
})
|
||||
chart3.parse(data2,"json");
|
||||
|
||||
var chart4 = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart4",
|
||||
value:"#sales#",
|
||||
item:{
|
||||
borderColor: "#000000",
|
||||
color: "#ffffff",
|
||||
borderWidth:1,
|
||||
radius:3
|
||||
},
|
||||
line:{
|
||||
color:"#3399ff",
|
||||
width:3
|
||||
},
|
||||
xAxis:{
|
||||
title:"Years",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start: 0,
|
||||
end: 10,
|
||||
step: 1,
|
||||
title:"Sales, mil",
|
||||
lines:false
|
||||
},
|
||||
tooltip:{
|
||||
template:"#year#"
|
||||
}
|
||||
})
|
||||
chart4.parse(data2,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<table>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart3" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart4" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,101 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Scales</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart1 = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
item:{
|
||||
borderColor: "#ffffff",
|
||||
color: "#000000"
|
||||
},
|
||||
line:{
|
||||
color:"#ff9900",
|
||||
width:3
|
||||
},
|
||||
yAxis:{},
|
||||
xAxis:{
|
||||
title:"Years",
|
||||
template:"#year#"
|
||||
}
|
||||
})
|
||||
chart1.parse(data,"json");
|
||||
|
||||
var chart2 = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
item:{
|
||||
borderColor: "#3399ff",
|
||||
color: "#ffffff"
|
||||
},
|
||||
line:{
|
||||
color:"#3399ff",
|
||||
width:3
|
||||
},
|
||||
xAxis:{
|
||||
title:"Years",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
end:10,
|
||||
step:1,
|
||||
title:"Sales, million"
|
||||
},
|
||||
item:{
|
||||
borderColor: "#3399ff",
|
||||
color: "#ffffff"
|
||||
}
|
||||
})
|
||||
chart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<table>
|
||||
<tr>
|
||||
<td>Automatic vertical scale</td>
|
||||
<td>Custom vertical scale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Initialization</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart = new dhtmlXChart({
|
||||
view:"spline",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
item:{
|
||||
borderColor: "#ffffff",
|
||||
color: "#000000"
|
||||
},
|
||||
line:{
|
||||
color:"#ff9900",
|
||||
width:3
|
||||
},
|
||||
padding:{
|
||||
left:15
|
||||
}
|
||||
})
|
||||
chart.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chart" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,94 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Scales</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ "companyA":"-1.9", "companyB":1, year:"2000" },
|
||||
{ "companyA":"-0.8", "companyB":0.8, year:"2001" },
|
||||
{ "companyA":"3.4", "companyB":1.9, year:"2002" },
|
||||
{ "companyA":"4.1", "companyB":2.5, year:"2003" },
|
||||
{ "companyA":"4.3", "companyB":3.1, year:"2004" },
|
||||
{ "companyA":"5.9", "companyB":4.5, year:"2005" },
|
||||
{ "companyA":"6.1", "companyB":5.7, year:"2006" },
|
||||
{ "companyA":"6.5", "companyB":7.2, year:"2007" },
|
||||
{ "companyA":"5.2", "companyB":6.5, year:"2008" },
|
||||
{ "companyA":"4.8", "companyB":6.8, year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart1 = new dhtmlXChart({
|
||||
view:"line",
|
||||
container:"chart1",
|
||||
value:"#companyA#",
|
||||
item:{
|
||||
borderColor: "#3399ff",
|
||||
color: "#ffffff"
|
||||
},
|
||||
line:{
|
||||
color:"#3399ff",
|
||||
width:3
|
||||
},
|
||||
xAxis:{
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:-2,
|
||||
step:1,
|
||||
end:8
|
||||
},
|
||||
padding:{
|
||||
left:35,
|
||||
bottom:20
|
||||
},
|
||||
origin:0,
|
||||
legend:{
|
||||
layout:"x",
|
||||
width: 75,
|
||||
align:"center",
|
||||
valign:"bottom",
|
||||
marker:{
|
||||
type:"round",
|
||||
width:15
|
||||
},
|
||||
values:[
|
||||
{text:"company A",color:"#3399ff"},
|
||||
{text:"company B",color:"#66cc00"}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
chart1.addSeries({
|
||||
value:"#companyB#",
|
||||
item:{
|
||||
borderColor: "#66cc00",
|
||||
color: "#ffffff"
|
||||
},
|
||||
line:{
|
||||
color:"#66cc00",
|
||||
width:3
|
||||
}
|
||||
})
|
||||
chart1.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<table>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:500px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,74 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>PieChart: Initiazation</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
width:30,
|
||||
gradient:true,
|
||||
border:false
|
||||
})
|
||||
barChart1.parse(data,"json");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#66ccff",
|
||||
gradient:"3d",
|
||||
//border:false,
|
||||
width:25,
|
||||
padding:{
|
||||
bottom:0,
|
||||
right:50,
|
||||
left:50
|
||||
}
|
||||
});
|
||||
barChart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<h1>BarChart: Initiazation</h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,80 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>PieChart: Initiazation</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
</head>
|
||||
<body >
|
||||
<h1>BarChart: Initiazation</h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
|
||||
var barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#66cc33",
|
||||
width:50,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
}
|
||||
})
|
||||
barChart1.parse(data,"json");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Years",
|
||||
template:"#year#"
|
||||
}
|
||||
});
|
||||
barChart2.parse(data,"json");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,99 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>PieChart: Initiazation</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
</head>
|
||||
<body >
|
||||
<h1>BarChart: Scales</h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Custom vertical scale and origin</td>
|
||||
<td>Automatic vertical scale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"-2.0", year:"2000" },
|
||||
{ sales:"-0.4", year:"2001" },
|
||||
{ sales:"1.1", year:"2002" },
|
||||
{ sales:"3.3", year:"2003" },
|
||||
{ sales:"1.2", year:"2004" },
|
||||
{ sales:"1.8", year:"2005" },
|
||||
{ sales:"4.1", year:"2006" },
|
||||
{ sales:"5.5", year:"2007" },
|
||||
{ sales:"3.5", year:"2008" },
|
||||
{ sales:"1.8", year:"2009" }
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
var barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
width:30,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
template:"#year#",
|
||||
title:"Year"
|
||||
},
|
||||
|
||||
yAxis:{
|
||||
start:-3,
|
||||
end:7,
|
||||
step:1,
|
||||
title:"Profit"
|
||||
},
|
||||
origin:0,
|
||||
gradient:true,
|
||||
border:false
|
||||
})
|
||||
barChart1.parse(data,"json");
|
||||
|
||||
|
||||
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:30,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
template:"#year#",
|
||||
title:"Year"
|
||||
},
|
||||
yAxis:{
|
||||
title:"Profit"
|
||||
}
|
||||
|
||||
});
|
||||
barChart2.parse(data,"json");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,207 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Chart</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
</head>
|
||||
<body >
|
||||
<h1>Chart</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart3" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart4" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart5" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart6" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
|
||||
var barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
alpha:function(data){
|
||||
return data.sales/10;
|
||||
},
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#66cc33",
|
||||
width:50,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
end:10,
|
||||
step:1,
|
||||
title:"Sales, million"
|
||||
}
|
||||
})
|
||||
barChart1.parse(data,"json");
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:2,
|
||||
border:false,
|
||||
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Years",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
end:10,
|
||||
step:1,
|
||||
title:"Sales,<br/>million"
|
||||
}
|
||||
|
||||
})
|
||||
barChart2.parse(data,"json");
|
||||
|
||||
|
||||
var barChart3 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart3",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:35,
|
||||
border:false,
|
||||
gradient:true,
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
end:10,
|
||||
step:1,
|
||||
title:"Sales,<br/>million"
|
||||
}
|
||||
});
|
||||
barChart3.parse(data,"json");
|
||||
|
||||
var barChart4 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
alpha:function(data){
|
||||
return data.sales/10;
|
||||
},
|
||||
container:"chart4",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:50,
|
||||
gradient:function(gradient){
|
||||
gradient.addColorStop(1.0,"#FF0000");
|
||||
gradient.addColorStop(0.3,"#FFFF00");
|
||||
gradient.addColorStop(0.0,"#00FF22");
|
||||
},
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
end:10,
|
||||
step:1,
|
||||
title:"Sales,<br/>million"
|
||||
}
|
||||
})
|
||||
barChart4.parse(data,"json");
|
||||
|
||||
|
||||
var barChart5 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart5",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:35,
|
||||
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
end:10,
|
||||
step:1,
|
||||
title:"Sales,<br/>million"
|
||||
}
|
||||
})
|
||||
barChart5.parse(data,"json");
|
||||
|
||||
var barChart6 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
alpha:function(data){
|
||||
return data.sales/10;
|
||||
},
|
||||
container:"chart6",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#66cc33",
|
||||
border:false,
|
||||
width:30,
|
||||
radius:0,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
end:10,
|
||||
step:1,
|
||||
title:"Sales,<br/>million"
|
||||
}
|
||||
})
|
||||
barChart6.parse(data,"json");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,87 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>StackedBar Chart</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1>StackedBar Chart</h1>
|
||||
<div id="chart1" style="width:450px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
|
||||
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0",sales1:"3.4",sales2:"1.2",sales3:"6.9", year:"2000" },
|
||||
{ sales:"5.0",sales1:"5.0",sales2:"5.0",sales3:"5.0", year:"2001" },
|
||||
{ sales:"3.4",sales1:"4.7",sales2:"1.9",sales3:"5.5", year:"2002" }
|
||||
];
|
||||
function init(){
|
||||
var barChart1 = new dhtmlXChart({
|
||||
view:"stackedBar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:60,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
title:"Sales,million"
|
||||
},
|
||||
gradient:"3d",
|
||||
//border:false,
|
||||
color: "#66cc33",
|
||||
legend:{
|
||||
values:[{text:"department A",color:"#66cc33"},{text:"department B",color:"#ff9933"},{text:"department C",color:"#ffff99"},{text:"department D",color:"#66ffcc"}],
|
||||
valign:"top",
|
||||
align:"right",
|
||||
width:120,
|
||||
layout:"y",
|
||||
marker:{
|
||||
width:15,
|
||||
type:"round"
|
||||
}
|
||||
}
|
||||
})
|
||||
barChart1.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#ff9933",
|
||||
label:"#sales1#",
|
||||
tooltip:{
|
||||
template:"#sales1#"
|
||||
}
|
||||
});
|
||||
barChart1.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#ffff99",
|
||||
label:"#sales2#",
|
||||
tooltip:{
|
||||
template:"#sales2#"
|
||||
}
|
||||
});
|
||||
barChart1.addSeries({
|
||||
value:"#sales3#",
|
||||
color:"#66ffcc",
|
||||
label:"#sales3#",
|
||||
tooltip:{
|
||||
template:"#sales3#"
|
||||
}
|
||||
});
|
||||
barChart1.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,81 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Series</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
</head>
|
||||
<body >
|
||||
<h1>Series</h1>
|
||||
|
||||
<div id="chart" style="width:500px;height:300px;border:1px solid #A4BED4;"></div>
|
||||
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"4.2",sales1:"3.4",sales2:"1.2", year:"2000" },
|
||||
{ sales:"3.8",sales1:"4.5",sales2:"2.5", year:"2001" },
|
||||
{ sales:"3.4",sales1:"4.7",sales2:"1.9", year:"2002" }
|
||||
];
|
||||
|
||||
|
||||
|
||||
var barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:30,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
step:1,
|
||||
end:5,
|
||||
title:"Sales,million"
|
||||
},
|
||||
gradient:true,
|
||||
border:false,
|
||||
color: "#66cc33",
|
||||
legend:{
|
||||
values:[{text:"department A",color:"#66cc33"},{text:"department B",color:"#ff9933"},{text:"department C",color:"#ffff99"}],
|
||||
valign:"top",
|
||||
align:"center",
|
||||
width:120,
|
||||
layout:"x",
|
||||
marker:{
|
||||
width:15,
|
||||
type:"round"
|
||||
}
|
||||
}
|
||||
})
|
||||
barChart.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#ff9933",
|
||||
label:"#sales1#"
|
||||
});
|
||||
barChart.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#ffff99",
|
||||
label:"#sales2#"
|
||||
});
|
||||
barChart.parse(data,"json");
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,120 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Horizontal bar Chart</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
</head>
|
||||
<body >
|
||||
<h3>Horizontal bar Chart</h3>
|
||||
|
||||
<table>
|
||||
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:450px;height:350px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:450px;height:350px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
|
||||
var data2 = [
|
||||
{ sales:"3.0",sales1:"3.4",sales2:"1.2",sales3:"6.9", year:"2007" },
|
||||
{ sales:"3.8",sales1:"4.5",sales2:"2.5",sales3:"7.5", year:"2008" },
|
||||
{ sales:"3.4",sales1:"4.7",sales2:"1.9",sales3:"5.5", year:"2009" }
|
||||
];
|
||||
var barChart1 = new dhtmlXChart({
|
||||
view:"barH",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
width:50,
|
||||
label: "#sales#",
|
||||
gradient:"3d",
|
||||
color:"#ffcc00",
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
lines: true
|
||||
},
|
||||
yAxis:{
|
||||
title:"Year",
|
||||
template:"#year#"
|
||||
},
|
||||
padding:{
|
||||
left:75,
|
||||
right:30
|
||||
}
|
||||
})
|
||||
barChart1.parse(data,"json");
|
||||
|
||||
|
||||
|
||||
var barChart2 = new dhtmlXChart({
|
||||
view:"barH",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
width:30,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year"
|
||||
},
|
||||
yAxis:{
|
||||
title:"Year",
|
||||
template:"#year#"
|
||||
},
|
||||
gradient:true,
|
||||
border:false,
|
||||
color: "#66cc33",
|
||||
legend:{
|
||||
values:[{text:"department A",color:"#66cc33"},{text:"department B",color:"#ff9933"},{text:"department C",color:"#ffff99"}],
|
||||
|
||||
width:120,
|
||||
align:"right",
|
||||
valign:"middle",
|
||||
marker:{
|
||||
width:15,
|
||||
type:"round"
|
||||
}
|
||||
},
|
||||
padding:{
|
||||
left:65
|
||||
}
|
||||
});
|
||||
barChart2.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#ff9933",
|
||||
label:"#sales1#"
|
||||
});
|
||||
barChart2.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#ffff99",
|
||||
label:"#sales2#"
|
||||
});
|
||||
barChart2.parse(data2,"json");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,75 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Horizontal Stacked Bars</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
|
||||
var data = [
|
||||
{ sales:"3.0",sales1:"3.4",sales2:"1.2",sales3:"6.9", year:"2007" },
|
||||
{ sales:"5.0",sales1:"5.0",sales2:"5.0",sales3:"5.0", year:"2008" },
|
||||
{ sales:"3.4",sales1:"4.7",sales2:"1.9",sales3:"5.5", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
barChart = new dhtmlXChart({
|
||||
view:"stackedBarH",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
width:50,
|
||||
label: "#sales#",
|
||||
gradient:"3d",
|
||||
color: "#66cc33",
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
lines: false
|
||||
},
|
||||
yAxis:{
|
||||
title:"Year",
|
||||
template:"#year#"
|
||||
},
|
||||
padding:{left:75},
|
||||
legend:{
|
||||
values:[{text:"department A",color:"#66cc33"},{text:"department B",color:"#ff9933"},{text:"department C",color:"#ffff66"},{text:"department D",color:"#66ffcc"}],
|
||||
valign:"top",
|
||||
align:"left",
|
||||
width:120,
|
||||
layout:"x",
|
||||
marker:{
|
||||
width:15,
|
||||
type:"round"
|
||||
}
|
||||
}
|
||||
})
|
||||
barChart.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#ff9933",
|
||||
label:"#sales1#"
|
||||
});
|
||||
barChart.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#ffff66",
|
||||
label:"#sales2#"
|
||||
});
|
||||
barChart.addSeries({
|
||||
value:"#sales3#",
|
||||
color:"#66ffcc",
|
||||
label:"#sales3#"
|
||||
});
|
||||
barChart.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chart" style="width:480px;height:350px;border:1px solid #A4BED4;"></div></td>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Initialization</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"7.6", year:"2005" },
|
||||
{ sales:"7.8", year:"2006" },
|
||||
{ sales:"7.2", year:"2007" },
|
||||
{ sales:"5.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart = new dhtmlXChart({
|
||||
view:"area",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
label:"#year#",
|
||||
color:"#00ccff",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
|
||||
alpha:0.8,
|
||||
padding:{
|
||||
left:0,
|
||||
right:0,
|
||||
bottom:0
|
||||
}
|
||||
})
|
||||
chart.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="chart" style="width:450px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Scales</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<style>
|
||||
.dhx_axis_item_x{
|
||||
font-size: 10px
|
||||
}
|
||||
.dhx_axis_item_y{
|
||||
font-size: 10px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"7.6", year:"2005" },
|
||||
{ sales:"7.8", year:"2006" },
|
||||
{ sales:"7.2", year:"2007" },
|
||||
{ sales:"5.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart1 = new dhtmlXChart({
|
||||
view:"area",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
color:"#00ccff",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
padding:{
|
||||
left:30
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
step:1,
|
||||
end:10
|
||||
},
|
||||
xAxis:{
|
||||
lines:true,
|
||||
title:"sales per year",
|
||||
template:"#year#"
|
||||
}
|
||||
})
|
||||
chart1.parse(data,"json");
|
||||
|
||||
var chart2 = new dhtmlXChart({
|
||||
view:"area",
|
||||
container:"chart2",
|
||||
value:"#sales#",
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
color:"#00ccff",
|
||||
xAxis:{
|
||||
title:"sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
yAxis:{
|
||||
},
|
||||
padding:{
|
||||
left:30
|
||||
},
|
||||
item:{
|
||||
borderColor: "#3399ff",
|
||||
color: "#ffffff"
|
||||
}
|
||||
})
|
||||
chart2.parse(data,"json");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<table>
|
||||
<tr>
|
||||
<td>Custom vertical scale</td>
|
||||
<td>Automatic vertical scale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:470px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
<td><div id="chart2" style="width:470px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Scales</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<style>
|
||||
.dhx_axis_item_x{
|
||||
font-size: 10px
|
||||
}
|
||||
.dhx_axis_item_y{
|
||||
font-size: 10px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:3.0, sales1:2.8, sales2:3.4, year:"2000" },
|
||||
{ sales:3.8, sales1:2.5, sales2:2.0, year:"2001" },
|
||||
{ sales:3.4, sales1:1.7, sales2:3.1, year:"2002" },
|
||||
{ sales:4.1, sales1:2.7, sales2:3.5, year:"2003" },
|
||||
{ sales:4.3, sales1:3.6, sales2:4.0, year:"2004" },
|
||||
{ sales:7.6, sales1:3.1, sales2:4.9, year:"2005" },
|
||||
{ sales:7.8, sales1:3.9, sales2:5.2, year:"2006" },
|
||||
{ sales:7.2, sales1:3.6, sales2:5.6, year:"2007" },
|
||||
{ sales:5.3, sales1:2.9, sales2:4.1, year:"2008" },
|
||||
{ sales:4.8, sales1:2.1, sales2:3.9, year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart1 = new dhtmlXChart({
|
||||
view:"area",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
color:"#00ccff",
|
||||
alpha:0.6,
|
||||
padding:{
|
||||
left:30
|
||||
},
|
||||
yAxis:{
|
||||
start:0,
|
||||
step:1,
|
||||
end:8
|
||||
},
|
||||
xAxis:{
|
||||
lines:true,
|
||||
title:"sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
legend:{
|
||||
layout:"x",
|
||||
width: 75,
|
||||
align:"center",
|
||||
valign:"top",
|
||||
marker:{
|
||||
type:"round",
|
||||
width:15
|
||||
},
|
||||
values:[
|
||||
{text:"company A",color:"#00ccff"},
|
||||
{text:"company B",color:"#0000ff"},
|
||||
{text:"company C",color:"#cc33ff"}
|
||||
]
|
||||
}
|
||||
})
|
||||
chart1.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#0000ff"
|
||||
})
|
||||
chart1.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#cc33ff"
|
||||
})
|
||||
chart1.parse(data,"json");
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<div id="chart" style="width:470px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,88 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Scales</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<style>
|
||||
.dhx_axis_item_x{
|
||||
font-size: 10px
|
||||
}
|
||||
.dhx_axis_item_y{
|
||||
font-size: 10px
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:3.0, sales1:2.8, sales2:3.9, year:"2000" },
|
||||
{ sales:3.8, sales1:2.5, sales2:2.0, year:"2001" },
|
||||
{ sales:3.4, sales1:1.7, sales2:3.1, year:"2002" },
|
||||
{ sales:4.1, sales1:2.7, sales2:3.5, year:"2003" },
|
||||
{ sales:4.3, sales1:3.6, sales2:4.0, year:"2004" },
|
||||
{ sales:7.6, sales1:3.1, sales2:4.9, year:"2005" },
|
||||
{ sales:7.8, sales1:3.9, sales2:5.2, year:"2006" },
|
||||
{ sales:7.2, sales1:3.6, sales2:5.6, year:"2007" },
|
||||
{ sales:5.3, sales1:2.9, sales2:4.1, year:"2008" },
|
||||
{ sales:4.8, sales1:2.1, sales2:3.9, year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
var chart1 = new dhtmlXChart({
|
||||
view:"stackedArea",
|
||||
container:"chart",
|
||||
value:"#sales#",
|
||||
color:"#00ccff",
|
||||
alpha:0.6,
|
||||
padding:{
|
||||
left:30
|
||||
},
|
||||
yAxis:{
|
||||
|
||||
},
|
||||
xAxis:{
|
||||
lines:true,
|
||||
title:"sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
legend:{
|
||||
layout:"x",
|
||||
width: 75,
|
||||
align:"center",
|
||||
valign:"top",
|
||||
marker:{
|
||||
type:"round",
|
||||
width:15
|
||||
},
|
||||
values:[
|
||||
{text:"company A",color:"#00ccff"},
|
||||
{text:"company B",color:"#0000ff"},
|
||||
{text:"company C",color:"#cc33ff"}
|
||||
]
|
||||
}
|
||||
})
|
||||
chart1.addSeries({
|
||||
value:"#sales1#",
|
||||
color:"#0000ff"
|
||||
})
|
||||
chart1.addSeries({
|
||||
value:"#sales2#",
|
||||
color:"#cc33ff"
|
||||
})
|
||||
chart1.parse(data,"json");
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<div id="chart" style="width:470px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,83 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Adding</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
var barChart1;
|
||||
|
||||
window.onload = function(){
|
||||
barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#b3e025",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:50,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
padding:{
|
||||
top:20,
|
||||
left:0,
|
||||
right:0
|
||||
}
|
||||
});
|
||||
barChart1.parse(data,"json");
|
||||
}
|
||||
|
||||
var counter = 2010;
|
||||
function add_new () {
|
||||
barChart1.add({
|
||||
year:counter,
|
||||
sales:(Math.random()*5).toFixed(2)
|
||||
});
|
||||
counter++;
|
||||
}
|
||||
function delete_first(){
|
||||
barChart1.remove(barChart1.first());
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:750px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<input type="button" value="add" onclick="add_new()">
|
||||
<input type="button" value="delete" onclick="delete_first()">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,96 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Events</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
var barChart1;
|
||||
window.onload = function(){
|
||||
barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#b3e025",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:50,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
padding:{
|
||||
top:20,
|
||||
left:0,
|
||||
right:0
|
||||
}
|
||||
});
|
||||
barChart1.parse(data,"json");
|
||||
barChart1.attachEvent("onMouseMove", function(id){
|
||||
id = barChart1.get(id).year;
|
||||
log("onMouseMove", id);
|
||||
return true;
|
||||
});
|
||||
barChart1.attachEvent("onMouseOut", function(id){
|
||||
log("onMouseOut", id);
|
||||
return true;
|
||||
});
|
||||
|
||||
barChart1.attachEvent("onItemClick", function(id){
|
||||
id = barChart1.get(id).year;
|
||||
log("onItemClick", id);
|
||||
return true;
|
||||
});
|
||||
barChart1.attachEvent("onItemDblClick", function(id){
|
||||
id = barChart1.get(id).year;
|
||||
log("onItemDblClick", id);
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function log(name, id){
|
||||
var t = document.createElement("DIV");
|
||||
t.innerHTML = name+" for element "+id;
|
||||
|
||||
var p = document.getElementById("log_div");
|
||||
p.insertBefore(t, p.firstChild);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:750px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="log_div" style="widht:950px; height:300px; font-family:Tahoma;overflow:auto"></div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,73 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Sorting</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
var barChart1;
|
||||
|
||||
window.onload = function(){
|
||||
barChart1 = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#b3e025",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:50,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
padding:{
|
||||
top:20,
|
||||
left:0,
|
||||
right:0
|
||||
}
|
||||
});
|
||||
barChart1.parse(data,"json");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<table>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:750px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<input type="button" value="sort by sales, ASC" onclick="barChart1.sort('#sales#','asc');">
|
||||
<input type="button" value="sort by sales, DESC" onclick="barChart1.sort('#sales#','desc');">
|
||||
<input type="button" value="sort by year, ASC" onclick="barChart1.sort('#year#','asc');">
|
||||
<input type="button" value="sort by year, DESC" onclick="barChart1.sort('#year#','desc');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,81 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Filtering</title>
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
window.onload = function(){
|
||||
barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart1",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
color:"#b3e025",
|
||||
gradient:true,
|
||||
border:false,
|
||||
width:50,
|
||||
tooltip:{
|
||||
template:"#sales#"
|
||||
},
|
||||
xAxis:{
|
||||
title:"Sales per year",
|
||||
template:"#year#"
|
||||
},
|
||||
padding:{
|
||||
top:30,
|
||||
left:0,
|
||||
right:0
|
||||
}
|
||||
});
|
||||
barChart.parse(data,"json");
|
||||
}
|
||||
|
||||
function filter_year(){
|
||||
barChart.filter(function(obj){
|
||||
return obj.year >2005;
|
||||
})
|
||||
}
|
||||
function filter_sales(){
|
||||
barChart.filter(function(obj){
|
||||
return obj.sales < 8;
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td><div id="chart1" style="width:750px;height:300px;border:1px solid #A4BED4;"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<input type="button" value="show all" onclick="barChart.filter();">
|
||||
<input type="button" value="show year > 2005" onclick="filter_year()">
|
||||
<input type="button" value="show sales < 8" onclick="filter_sales()">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,70 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Integration with grid</title>
|
||||
<link rel='STYLESHEET' type='text/css' href='../../../dhtmlxGrid/codebase/dhtmlxgrid.css'>
|
||||
<link rel='STYLESHEET' type='text/css' href='../../../dhtmlxGrid/codebase/skins/dhtmlxgrid_dhx_skyblue.css'>
|
||||
<script src='../../../dhtmlxGrid/codebase/dhtmlxcommon.js'></script>
|
||||
<script src='../../../dhtmlxGrid/codebase/dhtmlxgrid.js'></script>
|
||||
<script src='../../../dhtmlxGrid/codebase/dhtmlxgridcell.js'></script>
|
||||
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var barChart;
|
||||
window.onload = function(){
|
||||
barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
color:"#66ccff",
|
||||
gradient:"3d",
|
||||
container:"chart_container",
|
||||
value:"#data0#",
|
||||
label:"#data0#",
|
||||
radius:3,
|
||||
tooltip:{
|
||||
template:"#data0#"
|
||||
},
|
||||
width:30,
|
||||
origin:0,
|
||||
yAxis:{},
|
||||
xAxis:{
|
||||
template:function(){return ""}
|
||||
},
|
||||
border:false
|
||||
});
|
||||
|
||||
function refresh_chart(){
|
||||
barChart.clearAll();
|
||||
barChart.parse(mygrid,"dhtmlxgrid");
|
||||
};
|
||||
|
||||
mygrid = new dhtmlXGridObject('gridbox');
|
||||
mygrid.setImagePath('../../../dhtmlxGrid/codebase/imgs/');
|
||||
mygrid.setSkin("dhx_skyblue")
|
||||
mygrid.loadXML("../../../dhtmlxGrid/samples/common/gridH.xml",refresh_chart);
|
||||
mygrid.attachEvent("onEditCell",function(stage){
|
||||
if (stage == 2)
|
||||
refresh_chart();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="gridbox" style="width:600px; height:270px; background-color:white;"></div>
|
||||
<hr>
|
||||
<div id="chart_container" style="width:500px;height:300px;"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,79 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Integration with Grid and Grouping</title>
|
||||
<link rel='STYLESHEET' type='text/css' href='../../../dhtmlxGrid/codebase/dhtmlxgrid.css'>
|
||||
<link rel='STYLESHEET' type='text/css' href='../../../dhtmlxGrid/codebase/skins/dhtmlxgrid_dhx_skyblue.css'>
|
||||
<script src='../../../dhtmlxGrid/codebase/dhtmlxcommon.js'></script>
|
||||
<script src='../../../dhtmlxGrid/codebase/dhtmlxgrid.js'></script>
|
||||
<script src='../../../dhtmlxGrid/codebase/dhtmlxgridcell.js'></script>
|
||||
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
<script>
|
||||
var barChart;
|
||||
window.onload = function(){
|
||||
barChart = new dhtmlXChart({
|
||||
view:"bar",
|
||||
container:"chart_container",
|
||||
value:"#sales#",
|
||||
label:"#sales#",
|
||||
sort:{
|
||||
by:"#sales#",
|
||||
as:"int"
|
||||
},
|
||||
group:{
|
||||
by:"#data2#",
|
||||
map:{
|
||||
author:["#data2#"],
|
||||
sales:["#data0#","sum"]
|
||||
}
|
||||
},
|
||||
xAxis:{
|
||||
template:"#author#"
|
||||
},
|
||||
padding:{
|
||||
left:0,
|
||||
right:0
|
||||
},
|
||||
color:"#45abf5",
|
||||
gradient:true,
|
||||
width:50,
|
||||
border:false
|
||||
});
|
||||
|
||||
function refresh_chart(){
|
||||
barChart.clearAll();
|
||||
barChart.parse(mygrid,"dhtmlxgrid");
|
||||
};
|
||||
|
||||
mygrid = new dhtmlXGridObject('gridbox');
|
||||
mygrid.setImagePath('../../../dhtmlxGrid/codebase/imgs/');
|
||||
mygrid.setSkin("dhx_skyblue")
|
||||
mygrid.loadXML("../../../dhtmlxGrid/samples/common/gridH.xml",refresh_chart);
|
||||
mygrid.attachEvent("onEditCell",function(stage){
|
||||
if (stage == 2)
|
||||
refresh_chart();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="gridbox" style="width:600px; height:270px; background-color:white;"></div>
|
||||
<hr>
|
||||
<div id="chart_container" style="width:600px;height:300px;"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,77 @@
|
|||
<!--conf
|
||||
<sample>
|
||||
<product version="2.6" edition="std"/>
|
||||
<modifications>
|
||||
<modified date="100609"/>
|
||||
</modifications>
|
||||
</sample>
|
||||
-->
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Integration with dhtmlxWindows</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../../../dhtmlxWindows/codebase/dhtmlxwindows.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../../dhtmlxWindows/codebase/skins/dhtmlxwindows_dhx_skyblue.css">
|
||||
|
||||
<script src="../../../dhtmlxWindows/codebase/dhtmlxcommon.js"></script>
|
||||
<script src="../../../dhtmlxWindows/codebase/dhtmlxwindows.js"></script>
|
||||
<script src="../../../dhtmlxWindows/codebase/dhtmlxcontainer.js"></script>
|
||||
|
||||
<script src="../../codebase/dhtmlxchart.js" type="text/javascript"></script>
|
||||
<link rel="STYLESHEET" type="text/css" href="../../codebase/dhtmlxchart.css">
|
||||
|
||||
</head>
|
||||
<style type="text/css" media="screen">
|
||||
html, body{
|
||||
height:100%;
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
}
|
||||
</style>
|
||||
<body onload="doOnLoad();">
|
||||
|
||||
<script>
|
||||
var dhxWins
|
||||
var data = [
|
||||
{ sales:"3.0", year:"2000" },
|
||||
{ sales:"3.8", year:"2001" },
|
||||
{ sales:"3.4", year:"2002" },
|
||||
{ sales:"4.1", year:"2003" },
|
||||
{ sales:"4.3", year:"2004" },
|
||||
{ sales:"9.9", year:"2005" },
|
||||
{ sales:"7.4", year:"2006" },
|
||||
{ sales:"9.0", year:"2007" },
|
||||
{ sales:"7.3", year:"2008" },
|
||||
{ sales:"4.8", year:"2009" }
|
||||
];
|
||||
|
||||
|
||||
function doOnLoad() {
|
||||
dhxWinsParams = {
|
||||
image_path: "../../../dhtmlxWindows/codebase/imgs/",
|
||||
wins: [ {id: "w1", left: 230, top: 230, width: 420, height: 340}]
|
||||
};
|
||||
dhxWins = new dhtmlXWindows(dhxWinsParams);
|
||||
pieChart2 = dhxWins.window("w1").attachChart({
|
||||
view:"pie",
|
||||
value:"#sales#",
|
||||
pieInnerText:"#sales#",
|
||||
gradient:true,
|
||||
details:{
|
||||
width: 75,
|
||||
align:"right",
|
||||
valign:top,
|
||||
marker:{
|
||||
type:"round",
|
||||
width:15
|
||||
},
|
||||
template:"#year#"
|
||||
}
|
||||
});
|
||||
|
||||
pieChart2.parse(data,"json");
|
||||
};
|
||||
</script>
|
||||
</body>
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/*
|
||||
Copyright DHTMLX LTD. http://www.dhtmlx.com
|
||||
This version of Software is free for using in non-commercial applications.
|
||||
For commercial use please contact sales@dhtmlx.com to obtain license
|
||||
*/
|
||||
|
||||
$mysql_host = "localhost";
|
||||
$mysql_user = "root";
|
||||
$mysql_pasw = "";
|
||||
$mysql_db = "sampledb";
|
||||
|
||||
?>
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
$str = "<data>";
|
||||
|
||||
for ($i=1; $i <= 100; $i++) {
|
||||
$sales = rand(100,1000);
|
||||
$year = rand(1996,2009);
|
||||
$company = "Company ".rand(1,3);
|
||||
$str.="<item id='{$i}' sales='{$sales}' year='{$year}' company='{$company}'></item>";
|
||||
}
|
||||
|
||||
$str .= "</data>";
|
||||
|
||||
file_put_contents("stat.xml",$str);
|
||||
|
||||
?>
|
|
@ -0,0 +1,46 @@
|
|||
<data>
|
||||
<item id="1">
|
||||
<sales>2.9</sales>
|
||||
<year>2000</year>
|
||||
</item>
|
||||
<item id="2">
|
||||
<sales>3.5</sales>
|
||||
<year>2001</year>
|
||||
</item>
|
||||
<item id="3">
|
||||
<sales>3.1</sales>
|
||||
<year>2002</year>
|
||||
</item>
|
||||
<item id="4">
|
||||
<sales>4.2</sales>
|
||||
<year>2003</year>
|
||||
</item>
|
||||
<item id="5">
|
||||
<sales>4.5</sales>
|
||||
<year>2004</year>
|
||||
</item>
|
||||
<item id="6">
|
||||
<sales>7.4</sales>
|
||||
<year>2005</year>
|
||||
</item>
|
||||
<item id="7">
|
||||
<sales>9.6</sales>
|
||||
<year>2006</year>
|
||||
</item>
|
||||
<item id="8">
|
||||
<sales>9</sales>
|
||||
<year>2007</year>
|
||||
</item>
|
||||
<item id="9">
|
||||
<sales>7.3</sales>
|
||||
<year>2008</year>
|
||||
</item>
|
||||
<item id="10">
|
||||
<sales>5.8</sales>
|
||||
<year>2009</year>
|
||||
</item>
|
||||
<item id="11">
|
||||
<sales>7.7</sales>
|
||||
<year>2010</year>
|
||||
</item>
|
||||
</data>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,7 @@
|
|||
Next samples
|
||||
08_integration\01_dhtmlxgrid.html
|
||||
08_integration\02_dhtmlxgrid_group.html
|
||||
08_integration\03_layout.html
|
||||
requires external components ( dhtmlxgrid and dhtmlxwindow )
|
||||
|
||||
Its recommended to run samples through any kind of webserver.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,479 @@
|
|||
/*---------------------------------------------------------
|
||||
* OpenERP base_graph
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.base_graph = function (openerp) {
|
||||
var COLOR_PALETTE = [
|
||||
'#cc99ff', '#ccccff', '#48D1CC', '#CFD784', '#8B7B8B', '#75507b',
|
||||
'#b0008c', '#ff0000', '#ff8e00', '#9000ff', '#0078ff', '#00ff00',
|
||||
'#e6ff00', '#ffff00', '#905000', '#9b0000', '#840067', '#9abe00',
|
||||
'#ffc900', '#510090', '#0000c9', '#009b00', '#75507b', '#3465a4',
|
||||
'#73d216', '#c17d11', '#edd400', '#fcaf3e', '#ef2929', '#ff00c9',
|
||||
'#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#f57900',
|
||||
'#cc0000', '#d400a8'];
|
||||
|
||||
QWeb.add_template('/base_graph/static/src/xml/base_graph.xml');
|
||||
openerp.base.views.add('graph', 'openerp.base_graph.GraphView');
|
||||
openerp.base_graph.GraphView = openerp.base.View.extend({
|
||||
|
||||
init: function(parent, element_id, dataset, view_id) {
|
||||
this._super(parent, element_id);
|
||||
this.view_manager = parent;
|
||||
this.dataset = dataset;
|
||||
this.dataset_index = 0;
|
||||
this.model = this.dataset.model;
|
||||
this.view_id = view_id;
|
||||
},
|
||||
do_show: function () {
|
||||
// TODO: re-trigger search
|
||||
this.$element.show();
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
},
|
||||
start: function() {
|
||||
return this.rpc("/base_graph/graphview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
|
||||
},
|
||||
on_loaded: function(data) {
|
||||
this.all_fields = data.all_fields;
|
||||
this.fields_view = data.fields_view;
|
||||
this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
|
||||
this.view_id = this.fields_view.view_id;
|
||||
this.chart = this.fields_view.arch.attrs.type || 'pie';
|
||||
this.fields = this.fields_view.fields;
|
||||
this.chart_info_fields = [];
|
||||
this.operator_field = '';
|
||||
this.operator_field_one = '';
|
||||
this.operator = [];
|
||||
this.group_field = [];
|
||||
this.orientation = this.fields_view.arch.attrs.orientation || '';
|
||||
this.elem_id = this.$element[0]['id'];
|
||||
|
||||
_.each(this.fields_view.arch.children, function (field) {
|
||||
if (field.attrs.operator) {
|
||||
this.operator.push(field.attrs.name);
|
||||
}
|
||||
else if (field.attrs.group) {
|
||||
this.group_field.push(field.attrs.name);
|
||||
}
|
||||
else {
|
||||
this.chart_info_fields.push(field.attrs.name);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.operator_field = this.operator[0];
|
||||
if(this.operator.length > 1){
|
||||
this.operator_field_one = this.operator[1];
|
||||
}
|
||||
if(this.operator == ''){
|
||||
this.operator_field = this.chart_info_fields[1];
|
||||
}
|
||||
this.chart_info = this.chart_info_fields[0];
|
||||
this.x_title = this.fields[this.chart_info_fields[0]]['string'];
|
||||
this.y_title = this.fields[this.operator_field]['string'];
|
||||
this.load_chart();
|
||||
},
|
||||
|
||||
load_chart: function(data) {
|
||||
var self = this;
|
||||
var domain = false;
|
||||
if(data){
|
||||
this.x_title = this.all_fields[this.chart_info_fields]['string'];
|
||||
this.y_title = this.all_fields[this.operator_field]['string'];
|
||||
self.schedule_chart(data);
|
||||
}else{
|
||||
if(! _.isEmpty(this.view_manager.dataset.domain)){
|
||||
domain = this.view_manager.dataset.domain;
|
||||
}else if(! _.isEmpty(this.view_manager.action.domain)){
|
||||
domain = this.view_manager.action.domain;
|
||||
}
|
||||
this.dataset.domain = domain;
|
||||
this.dataset.context = this.view_manager.dataset.context;
|
||||
this.dataset.read_slice(_(this.fields).keys(), 0, false, function(res) {
|
||||
self.schedule_chart(res);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
schedule_chart: function(results) {
|
||||
this.$element.html(QWeb.render("GraphView", {"fields_view": this.fields_view, "chart": this.chart,'elem_id': this.elem_id}));
|
||||
|
||||
_.each(results, function (result) {
|
||||
_.each(result, function (field_value, field_name) {
|
||||
if (typeof field_value == 'object') {
|
||||
result[field_name] = field_value[field_value.length - 1];
|
||||
}
|
||||
if (typeof field_value == 'string') {
|
||||
var choices = this.all_fields[field_name]['selection'];
|
||||
_.each(choices, function (choice) {
|
||||
if (field_value == choice[0]) {
|
||||
result[field_name] = choice;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
var graph_data = {};
|
||||
_.each(results, function (result) {
|
||||
var group_key = [];
|
||||
if(this.group_field.length){
|
||||
_.each(this.group_field, function (res) {
|
||||
result[res] = (typeof result[res] == 'object') ? result[res][1] : result[res];
|
||||
group_key.push(result[res]);
|
||||
});
|
||||
}else{
|
||||
group_key.push(result[this.group_field]);
|
||||
}
|
||||
var column_key = result[this.chart_info_fields] + "_" + group_key;
|
||||
var column_descriptor = {};
|
||||
if (graph_data[column_key] == undefined) {
|
||||
column_descriptor[this.operator_field] = result[this.operator_field];
|
||||
if (this.operator.length > 1) {
|
||||
column_descriptor[this.operator_field_one] = result[this.operator_field_one];
|
||||
}
|
||||
column_descriptor[this.chart_info_fields] = result[this.chart_info_fields];
|
||||
if(this.group_field.length){
|
||||
_.each(this.group_field, function (res) {
|
||||
column_descriptor[res] = (typeof result[res] == 'object') ? result[res][1] : result[res];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
column_descriptor = graph_data[column_key];
|
||||
column_descriptor[this.operator_field] += result[this.operator_field];
|
||||
if (this.operator.length > 1) {
|
||||
column_descriptor[this.operator_field_one] += result[this.operator_field_one];
|
||||
}
|
||||
}
|
||||
graph_data[column_key] = column_descriptor;
|
||||
}, this);
|
||||
|
||||
if (this.chart == 'bar') {
|
||||
return this.schedule_bar(_.values(graph_data));
|
||||
} else if (this.chart == "pie") {
|
||||
return this.schedule_pie(_.values(graph_data));
|
||||
}
|
||||
},
|
||||
|
||||
schedule_bar: function(results) {
|
||||
var self = this;
|
||||
var view_chart = '';
|
||||
var group_list = [];
|
||||
var legend_list = [];
|
||||
var newkey = '', newkey_one;
|
||||
var string_legend = '';
|
||||
|
||||
if((self.group_field.length) && (this.operator.length <= 1)){
|
||||
view_chart = self.orientation == 'horizontal'? 'stackedBarH' : 'stackedBar';
|
||||
}else{
|
||||
view_chart = self.orientation == 'horizontal'? 'barH' : 'bar';
|
||||
}
|
||||
|
||||
_.each(results, function (result) {
|
||||
if ((self.group_field.length) && (this.operator.length <= 1)) {
|
||||
var legend_key = '';
|
||||
_.each(self.group_field, function (res) {
|
||||
result[res] = (typeof result[res] == 'object') ? result[res][1] : result[res];
|
||||
legend_key += result[res];
|
||||
});
|
||||
newkey = legend_key.replace(/\s+/g,'_').replace(/[^a-zA-Z 0-9]+/g,'_');
|
||||
string_legend = legend_key;
|
||||
} else {
|
||||
newkey = string_legend = "val";
|
||||
}
|
||||
|
||||
if (_.contains(group_list, newkey) && _.contains(legend_list, string_legend)) {
|
||||
return;
|
||||
}
|
||||
group_list.push(newkey);
|
||||
legend_list.push(string_legend);
|
||||
|
||||
if (this.operator.length > 1) {
|
||||
newkey_one = "val1";
|
||||
group_list.push(newkey_one);
|
||||
legend_list.push(newkey_one);
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (group_list.length <=1){
|
||||
group_list = [];
|
||||
legend_list = [];
|
||||
newkey = string_legend = "val";
|
||||
group_list.push(newkey);
|
||||
legend_list.push(string_legend);
|
||||
}
|
||||
|
||||
var abscissa_data = {};
|
||||
_.each(results, function (result) {
|
||||
var label = result[self.chart_info_fields],
|
||||
section = {};
|
||||
if ((self.group_field.length) && (group_list.length > 1) && (self.operator.length <= 1)){
|
||||
var legend_key_two = '';
|
||||
_.each(self.group_field, function (res) {
|
||||
result[res] = (typeof result[res] == 'object') ? result[res][1] : result[res];
|
||||
legend_key_two += result[res];
|
||||
});
|
||||
newkey = legend_key_two.replace(/\s+/g,'_').replace(/[^a-zA-Z 0-9]+/g,'_');
|
||||
}else{
|
||||
newkey = "val";
|
||||
}
|
||||
if (abscissa_data[label] == undefined){
|
||||
section[self.chart_info_fields] = label;
|
||||
_.each(group_list, function (group) {
|
||||
section[group] = 0;
|
||||
});
|
||||
} else {
|
||||
section = abscissa_data[label];
|
||||
}
|
||||
section[newkey] = result[self.operator_field];
|
||||
if (self.operator.length > 1){
|
||||
section[newkey_one] = result[self.operator_field_one];
|
||||
}
|
||||
abscissa_data[label] = section;
|
||||
});
|
||||
|
||||
//for legend color
|
||||
var grp_color = _.map(legend_list, function (group_legend, index) {
|
||||
var legend = {color: COLOR_PALETTE[index]};
|
||||
if (group_legend == "val"){
|
||||
legend['text'] = self.fields[self.operator_field]['string']
|
||||
}else if(group_legend == "val1"){
|
||||
legend['text'] = self.fields[self.operator_field_one]['string']
|
||||
}else{
|
||||
legend['text'] = group_legend;
|
||||
}
|
||||
return legend;
|
||||
});
|
||||
|
||||
//for axis's value and title
|
||||
var max,min,step;
|
||||
var maximum,minimum;
|
||||
if(_.isEmpty(abscissa_data)){
|
||||
max = 9;
|
||||
min = 0;
|
||||
step=1;
|
||||
}else{
|
||||
var max_min = [];
|
||||
_.each(abscissa_data, function (abscissa_datas) {
|
||||
_.each(group_list, function(res){
|
||||
max_min.push(abscissa_datas[res]);
|
||||
});
|
||||
});
|
||||
maximum = Math.max.apply(Math,max_min);
|
||||
minimum = Math.min.apply(Math,max_min);
|
||||
if (maximum == minimum){
|
||||
if (maximum == 0){
|
||||
max = 9;
|
||||
min = 0;
|
||||
step=1;
|
||||
}else if(maximum > 0){
|
||||
max = maximum + (10 - maximum % 10);
|
||||
min = 0;
|
||||
step = Math.round(max/10);
|
||||
}else{
|
||||
max = 0;
|
||||
min = minimum - (10 + minimum % 10);
|
||||
step = Math.round(Math.abs(min)/10);
|
||||
}
|
||||
}
|
||||
}
|
||||
var abscissa_description = {
|
||||
template: self.chart_info_fields,
|
||||
title: "<b>"+self.x_title+"</b>"
|
||||
};
|
||||
|
||||
var ordinate_description = {
|
||||
lines: true,
|
||||
title: "<b>"+self.y_title+"</b>",
|
||||
start: min,
|
||||
step: step,
|
||||
end: max
|
||||
};
|
||||
|
||||
var x_axis, y_axis, tooltip;
|
||||
if (self.orientation == 'horizontal'){
|
||||
x_axis = ordinate_description;
|
||||
y_axis = abscissa_description;
|
||||
}else{
|
||||
x_axis = abscissa_description;
|
||||
y_axis = ordinate_description;
|
||||
}
|
||||
tooltip = self.chart_info_fields;
|
||||
|
||||
var bar_chart = new dhtmlXChart({
|
||||
view: view_chart,
|
||||
container: self.elem_id+"-barchart",
|
||||
value:"#"+group_list[0]+"#",
|
||||
gradient: "3d",
|
||||
border: false,
|
||||
width: 1024,
|
||||
tooltip:{
|
||||
template:"#"+tooltip+"#"+","+grp_color[0]['text']+"="+"#"+group_list[0]+"#"
|
||||
},
|
||||
radius: 0,
|
||||
color:grp_color[0]['color'],
|
||||
origin:0,
|
||||
xAxis:{
|
||||
template:function(obj){
|
||||
if(x_axis['template']){
|
||||
var val = obj[x_axis['template']];
|
||||
val = (typeof val == 'object')?val[1]:(!val?'Undefined':val);
|
||||
if(val.length > 12){
|
||||
val = val.substring(0,12);
|
||||
}
|
||||
return val;
|
||||
}else{
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
title:x_axis['title'],
|
||||
lines:x_axis['lines']
|
||||
},
|
||||
yAxis:{
|
||||
template:function(obj){
|
||||
if(y_axis['template']){
|
||||
var vals = obj[y_axis['template']];
|
||||
vals = (typeof vals == 'object')?vals[1]:(!vals?'Undefined':vals);
|
||||
if(vals.length > 12){
|
||||
vals = vals.substring(0,12);
|
||||
}
|
||||
return vals;
|
||||
}else{
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
title:y_axis['title'],
|
||||
lines: y_axis['lines'],
|
||||
start:y_axis['start'],
|
||||
step:y_axis['step'],
|
||||
end:y_axis['end']
|
||||
},
|
||||
padding: {
|
||||
left: 75
|
||||
},
|
||||
legend: {
|
||||
values: grp_color,
|
||||
align:"left",
|
||||
valign:"top",
|
||||
layout: "x",
|
||||
marker:{
|
||||
type:"round",
|
||||
width:12
|
||||
}
|
||||
}
|
||||
});
|
||||
for (var m = 1; m<group_list.length;m++){
|
||||
bar_chart.addSeries({
|
||||
value: "#"+group_list[m]+"#",
|
||||
tooltip:{
|
||||
template:"#"+tooltip+"#"+","+grp_color[m]['text']+"="+"#"+group_list[m]+"#"
|
||||
},
|
||||
color: grp_color[m]['color']
|
||||
});
|
||||
}
|
||||
bar_chart.parse(_.values(abscissa_data), "json");
|
||||
jQuery("#"+self.elem_id+"-barchart").height(jQuery("#"+self.elem_id+"-barchart").height()+50);
|
||||
bar_chart.attachEvent("onItemClick", function(id) {
|
||||
self.open_list_view(bar_chart.get(id));
|
||||
});
|
||||
},
|
||||
schedule_pie: function(result) {
|
||||
var self = this;
|
||||
var chart = new dhtmlXChart({
|
||||
view:"pie3D",
|
||||
container:self.elem_id+"-piechart",
|
||||
value:"#"+self.operator_field+"#",
|
||||
pieInnerText:function(obj) {
|
||||
var sum = chart.sum("#"+self.operator_field+"#");
|
||||
var val = obj[self.operator_field] / sum * 100 ;
|
||||
return val.toFixed(1) + "%";
|
||||
},
|
||||
tooltip:{
|
||||
template:"#"+self.chart_info_fields+"#"+"="+"#"+self.operator_field+"#"
|
||||
},
|
||||
gradient:"3d",
|
||||
height: 20,
|
||||
radius: 200,
|
||||
legend: {
|
||||
width: 300,
|
||||
align:"left",
|
||||
valign:"top",
|
||||
layout: "x",
|
||||
marker:{
|
||||
type:"round",
|
||||
width:12
|
||||
},
|
||||
template:function(obj){
|
||||
var val = obj[self.chart_info_fields];
|
||||
val = (typeof val == 'object')?val[1]:val;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
});
|
||||
chart.parse(result,"json");
|
||||
chart.attachEvent("onItemClick", function(id) {
|
||||
self.open_list_view(chart.get(id));
|
||||
});
|
||||
},
|
||||
open_list_view : function (id){
|
||||
var self = this;
|
||||
if($(".dhx_tooltip").is(":visible")) {
|
||||
$(".dhx_tooltip").remove('div');
|
||||
}
|
||||
id = id[this.chart_info_fields];
|
||||
if (typeof id == 'object'){
|
||||
id = id[0];
|
||||
}
|
||||
|
||||
var record_id = "";
|
||||
this.dataset.model = this.model;
|
||||
if (typeof this.chart_info_fields == 'object'){
|
||||
record_id = this.chart_info_fields[0];
|
||||
}else{
|
||||
record_id = this.chart_info_fields;
|
||||
}
|
||||
this.dataset.domain = [[record_id, '=', id],['id','in',this.dataset.ids]];
|
||||
var modes = !!modes ? modes.split(",") : ["list", "form", "graph"];
|
||||
var views = [];
|
||||
_.each(modes, function(mode) {
|
||||
var view = [false, mode];
|
||||
if (self.fields.views && self.fields.views[mode]) {
|
||||
view.push(self.fields.views[mode]);
|
||||
}
|
||||
views.push(view);
|
||||
});
|
||||
this.session.action_manager.do_action({
|
||||
"res_model" : this.dataset.model,
|
||||
"domain" : this.dataset.domain,
|
||||
"views" : views,
|
||||
"type" : "ir.actions.act_window",
|
||||
"auto_search" : true,
|
||||
"view_type" : "list",
|
||||
"view_mode" : "list"
|
||||
});
|
||||
},
|
||||
|
||||
do_search: function(domains, contexts, groupbys) {
|
||||
var self = this;
|
||||
this.rpc('/base/session/eval_domain_and_context', {
|
||||
domains: domains,
|
||||
contexts: contexts,
|
||||
group_by_seq: groupbys
|
||||
}, function (results) {
|
||||
// TODO: handle non-empty results.group_by with read_group
|
||||
if(results.group_by && results.group_by != ''){
|
||||
self.chart_info_fields = results.group_by[0];
|
||||
}else{
|
||||
self.chart_info_fields = self.chart_info;
|
||||
}
|
||||
self.dataset.context = results.context;
|
||||
self.dataset.domain = results.domain;
|
||||
self.dataset.read_slice([], 0, false,function(response){
|
||||
self.load_chart(response);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them
|
||||
};
|
||||
// vim:et fdc=0 fdl=0:
|
|
@ -0,0 +1,4 @@
|
|||
<template>
|
||||
<div t-name="GraphView" t-att-id="elem_id+'-'+chart+'chart'"
|
||||
style="height:300px;position:relative;"/>
|
||||
</template>
|
|
@ -4,4 +4,5 @@
|
|||
"depends": [],
|
||||
"js": ["static/*/*.js", "static/*/js/*.js"],
|
||||
"css": [],
|
||||
'active': False,
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue