[MERGE]Merge latest trunk.
bzr revid: kch@tinyerp.com-20110803055358-cpavcx8x2t60jtk0
This commit is contained in:
commit
933c576955
|
@ -6,8 +6,11 @@
|
||||||
'js' : [
|
'js' : [
|
||||||
"static/lib/datejs/date-en-US.js",
|
"static/lib/datejs/date-en-US.js",
|
||||||
"static/lib/jquery/jquery-1.5.2.js",
|
"static/lib/jquery/jquery-1.5.2.js",
|
||||||
|
"static/lib/jquery.form/jquery.form.js",
|
||||||
|
"static/lib/jquery.validate/jquery.validate.js",
|
||||||
"static/lib/jquery.ba-bbq/jquery.ba-bbq.js",
|
"static/lib/jquery.ba-bbq/jquery.ba-bbq.js",
|
||||||
"static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js",
|
"static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js",
|
||||||
|
"static/lib/jquery.blockui/jquery.blockUI.js",
|
||||||
"static/lib/jquery.superfish/js/hoverIntent.js",
|
"static/lib/jquery.superfish/js/hoverIntent.js",
|
||||||
"static/lib/jquery.superfish/js/superfish.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-1.8.9.custom.min.js",
|
||||||
|
@ -17,12 +20,13 @@
|
||||||
"static/lib/qweb/qweb2.js",
|
"static/lib/qweb/qweb2.js",
|
||||||
"static/lib/underscore/underscore.js",
|
"static/lib/underscore/underscore.js",
|
||||||
"static/lib/underscore/underscore.string.js",
|
"static/lib/underscore/underscore.string.js",
|
||||||
"static/src/js/base.js",
|
"static/src/js/boot.js",
|
||||||
|
"static/src/js/core.js",
|
||||||
|
"static/src/js/dates.js",
|
||||||
"static/src/js/chrome.js",
|
"static/src/js/chrome.js",
|
||||||
"static/src/js/controller.js",
|
|
||||||
"static/src/js/views.js",
|
"static/src/js/views.js",
|
||||||
"static/src/js/data.js",
|
"static/src/js/data.js",
|
||||||
"static/src/js/dates.js",
|
"static/src/js/data_export.js",
|
||||||
"static/src/js/form.js",
|
"static/src/js/form.js",
|
||||||
"static/src/js/list.js",
|
"static/src/js/list.js",
|
||||||
"static/src/js/list-editable.js",
|
"static/src/js/list-editable.js",
|
||||||
|
@ -35,5 +39,6 @@
|
||||||
"static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css",
|
"static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css",
|
||||||
"static/lib/jquery.ui.notify/css/ui.notify.css",
|
"static/lib/jquery.ui.notify/css/ui.notify.css",
|
||||||
"static/src/css/base.css",
|
"static/src/css/base.css",
|
||||||
|
"static/src/css/data_export.css",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import base64, glob, os, re
|
import base64, glob, os, re
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
import operator
|
||||||
import simplejson
|
import simplejson
|
||||||
|
|
||||||
import openerpweb
|
import openerpweb
|
||||||
|
@ -10,7 +12,9 @@ import openerpweb.ast
|
||||||
import openerpweb.nonliterals
|
import openerpweb.nonliterals
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
|
import xmlrpclib
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
# Should move to openerpweb.Xml2Json
|
# Should move to openerpweb.Xml2Json
|
||||||
class Xml2Json:
|
class Xml2Json:
|
||||||
# xml2json-direct
|
# xml2json-direct
|
||||||
|
@ -151,16 +155,86 @@ class Database(openerpweb.Controller):
|
||||||
_cp_path = "/base/database"
|
_cp_path = "/base/database"
|
||||||
|
|
||||||
@openerpweb.jsonrequest
|
@openerpweb.jsonrequest
|
||||||
def get_databases_list(self, req):
|
def get_list(self, req):
|
||||||
proxy = req.session.proxy("db")
|
proxy = req.session.proxy("db")
|
||||||
dbs = proxy.list()
|
dbs = proxy.list()
|
||||||
h = req.httprequest.headers['Host'].split(':')[0]
|
h = req.httprequest.headers['Host'].split(':')[0]
|
||||||
d = h.split('.')[0]
|
d = h.split('.')[0]
|
||||||
r = cherrypy.config['openerp.dbfilter'].replace('%h',h).replace('%d',d)
|
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)]
|
||||||
dbs = [i for i in dbs if re.match(r,i)]
|
|
||||||
return {"db_list": dbs}
|
return {"db_list": dbs}
|
||||||
|
|
||||||
|
@openerpweb.jsonrequest
|
||||||
|
def progress(self, req, password, id):
|
||||||
|
return req.session.proxy('db').get_progress(password, id)
|
||||||
|
|
||||||
|
@openerpweb.jsonrequest
|
||||||
|
def create(self, req, fields):
|
||||||
|
|
||||||
|
params = dict(map(operator.itemgetter('name', 'value'), fields))
|
||||||
|
create_attrs = operator.itemgetter(
|
||||||
|
'super_admin_pwd', 'db_name', 'demo_data', 'db_lang', 'create_admin_pwd')(
|
||||||
|
params)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return req.session.proxy("db").create(*create_attrs)
|
||||||
|
except xmlrpclib.Fault, e:
|
||||||
|
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
|
||||||
|
return {'error': e.faultCode, 'title': 'Create Database'}
|
||||||
|
return {'error': 'Could not create database !', 'title': 'Create Database'}
|
||||||
|
|
||||||
|
@openerpweb.jsonrequest
|
||||||
|
def drop(self, req, fields):
|
||||||
|
password, db = operator.itemgetter(
|
||||||
|
'drop_pwd', 'drop_db')(
|
||||||
|
dict(map(operator.itemgetter('name', 'value'), fields)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return req.session.proxy("db").drop(password, db)
|
||||||
|
except xmlrpclib.Fault, e:
|
||||||
|
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
|
||||||
|
return {'error': e.faultCode, 'title': 'Drop Database'}
|
||||||
|
return {'error': 'Could not drop database !', 'title': 'Drop Database'}
|
||||||
|
|
||||||
|
@openerpweb.httprequest
|
||||||
|
def backup(self, req, backup_db, backup_pwd, token):
|
||||||
|
try:
|
||||||
|
db_dump = base64.decodestring(
|
||||||
|
req.session.proxy("db").dump(backup_pwd, backup_db))
|
||||||
|
cherrypy.response.headers['Content-Type'] = "application/octet-stream; charset=binary"
|
||||||
|
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="' + backup_db + '.dump"'
|
||||||
|
cherrypy.response.cookie['fileToken'] = token
|
||||||
|
cherrypy.response.cookie['fileToken']['path'] = '/'
|
||||||
|
return db_dump
|
||||||
|
except xmlrpclib.Fault, e:
|
||||||
|
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
|
||||||
|
return 'Backup Database|' + e.faultCode
|
||||||
|
return 'Backup Database|Could not generate database backup'
|
||||||
|
|
||||||
|
@openerpweb.httprequest
|
||||||
|
def restore(self, req, db_file, restore_pwd, new_db):
|
||||||
|
try:
|
||||||
|
data = base64.encodestring(db_file.file.read())
|
||||||
|
req.session.proxy("db").restore(restore_pwd, new_db, data)
|
||||||
|
return ''
|
||||||
|
except xmlrpclib.Fault, e:
|
||||||
|
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
|
||||||
|
raise cherrypy.HTTPError(403)
|
||||||
|
|
||||||
|
raise cherrypy.HTTPError()
|
||||||
|
|
||||||
|
@openerpweb.jsonrequest
|
||||||
|
def change_password(self, req, fields):
|
||||||
|
old_password, new_password = operator.itemgetter(
|
||||||
|
'old_pwd', 'new_pwd')(
|
||||||
|
dict(map(operator.itemgetter('name', 'value'), fields)))
|
||||||
|
try:
|
||||||
|
return req.session.proxy("db").change_admin_password(old_password, new_password)
|
||||||
|
except xmlrpclib.Fault, e:
|
||||||
|
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
|
||||||
|
return {'error': e.faultCode, 'title': 'Change Password'}
|
||||||
|
return {'error': 'Error, password not changed !', 'title': 'Change Password'}
|
||||||
|
|
||||||
class Session(openerpweb.Controller):
|
class Session(openerpweb.Controller):
|
||||||
_cp_path = "/base/session"
|
_cp_path = "/base/session"
|
||||||
|
|
||||||
|
@ -178,6 +252,16 @@ class Session(openerpweb.Controller):
|
||||||
return req.session.model('ir.ui.view_sc').get_sc(req.session._uid, "ir.ui.menu",
|
return req.session.model('ir.ui.view_sc').get_sc(req.session._uid, "ir.ui.menu",
|
||||||
req.session.eval_context(req.context))
|
req.session.eval_context(req.context))
|
||||||
|
|
||||||
|
@openerpweb.jsonrequest
|
||||||
|
def get_lang_list(self, req):
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
'lang_list': (req.session.proxy("db").list_lang() or []),
|
||||||
|
'error': ""
|
||||||
|
}
|
||||||
|
except Exception, e:
|
||||||
|
return {"error": e, "title": "Languages"}
|
||||||
|
|
||||||
@openerpweb.jsonrequest
|
@openerpweb.jsonrequest
|
||||||
def modules(self, req):
|
def modules(self, req):
|
||||||
# TODO query server for installed web modules
|
# TODO query server for installed web modules
|
||||||
|
@ -903,18 +987,231 @@ class Action(openerpweb.Controller):
|
||||||
return clean_action(req.session.model('ir.actions.server').run(
|
return clean_action(req.session.model('ir.actions.server').run(
|
||||||
[action_id], req.session.eval_context(req.context)), req.session)
|
[action_id], req.session.eval_context(req.context)), req.session)
|
||||||
|
|
||||||
|
def export_csv(fields, result):
|
||||||
|
fp = 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):
|
||||||
|
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()
|
||||||
|
workbook.save(fp)
|
||||||
|
fp.seek(0)
|
||||||
|
data = fp.read()
|
||||||
|
fp.close()
|
||||||
|
#return data.decode('ISO-8859-1')
|
||||||
|
return unicode(data, 'utf-8', 'replace')
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
class Import(View):
|
class Import(View):
|
||||||
_cp_path = "/base/import"
|
_cp_path = "/base/import"
|
||||||
|
|
||||||
@openerpweb.httprequest
|
@openerpweb.httprequest
|
||||||
def import_data(self, req, session_id, callback, model, id, csvfile, csvsep, csvdel, csvcode, csvskip, fields=[]):
|
def import_data(self, req, session_id, callback, model, id, csvfile, csvsep, csvdel, csvcode, csvskip, fields=[]):
|
||||||
import StringIO
|
import StringIO
|
||||||
|
|
||||||
context = req.session.eval_context(req.context)
|
context = req.session.eval_context(req.context)
|
||||||
modle_obj = req.session.model(model)
|
modle_obj = req.session.model(model)
|
||||||
|
|
||||||
res = None
|
res = None
|
||||||
content = csvfile.file.read()
|
content = csvfile.file.read()
|
||||||
print "\n content++++++++++++++++++++++++++++",content
|
|
||||||
input=StringIO.StringIO(content)
|
input=StringIO.StringIO(content)
|
||||||
limit = 0
|
limit = 0
|
||||||
data = []
|
data = []
|
||||||
|
|
|
@ -0,0 +1,499 @@
|
||||||
|
/*!
|
||||||
|
* jQuery blockUI plugin
|
||||||
|
* Version 2.39 (23-MAY-2011)
|
||||||
|
* @requires jQuery v1.2.3 or later
|
||||||
|
*
|
||||||
|
* Examples at: http://malsup.com/jquery/block/
|
||||||
|
* Copyright (c) 2007-2010 M. Alsup
|
||||||
|
* Dual licensed under the MIT and GPL licenses:
|
||||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*
|
||||||
|
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
|
||||||
|
*/
|
||||||
|
|
||||||
|
;(function($) {
|
||||||
|
|
||||||
|
if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
|
||||||
|
alert('blockUI requires jQuery v1.2.3 or later! You are using v' + $.fn.jquery);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn._fadeIn = $.fn.fadeIn;
|
||||||
|
|
||||||
|
var noOp = function() {};
|
||||||
|
|
||||||
|
// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
|
||||||
|
// retarded userAgent strings on Vista)
|
||||||
|
var mode = document.documentMode || 0;
|
||||||
|
var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
|
||||||
|
var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;
|
||||||
|
|
||||||
|
// global $ methods for blocking/unblocking the entire page
|
||||||
|
$.blockUI = function(opts) { install(window, opts); };
|
||||||
|
$.unblockUI = function(opts) { remove(window, opts); };
|
||||||
|
|
||||||
|
// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
|
||||||
|
$.growlUI = function(title, message, timeout, onClose) {
|
||||||
|
var $m = $('<div class="growlUI"></div>');
|
||||||
|
if (title) $m.append('<h1>'+title+'</h1>');
|
||||||
|
if (message) $m.append('<h2>'+message+'</h2>');
|
||||||
|
if (timeout == undefined) timeout = 3000;
|
||||||
|
$.blockUI({
|
||||||
|
message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
|
||||||
|
timeout: timeout, showOverlay: false,
|
||||||
|
onUnblock: onClose,
|
||||||
|
css: $.blockUI.defaults.growlCSS
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// plugin method for blocking element content
|
||||||
|
$.fn.block = function(opts) {
|
||||||
|
return this.unblock({ fadeOut: 0 }).each(function() {
|
||||||
|
if ($.css(this,'position') == 'static')
|
||||||
|
this.style.position = 'relative';
|
||||||
|
if ($.browser.msie)
|
||||||
|
this.style.zoom = 1; // force 'hasLayout'
|
||||||
|
install(this, opts);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// plugin method for unblocking element content
|
||||||
|
$.fn.unblock = function(opts) {
|
||||||
|
return this.each(function() {
|
||||||
|
remove(this, opts);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.blockUI.version = 2.39; // 2nd generation blocking at no extra cost!
|
||||||
|
|
||||||
|
// override these in your code to change the default behavior and style
|
||||||
|
$.blockUI.defaults = {
|
||||||
|
// message displayed when blocking (use null for no message)
|
||||||
|
message: '<h1>Please wait...</h1>',
|
||||||
|
|
||||||
|
title: null, // title string; only used when theme == true
|
||||||
|
draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
|
||||||
|
|
||||||
|
theme: false, // set to true to use with jQuery UI themes
|
||||||
|
|
||||||
|
// styles for the message when blocking; if you wish to disable
|
||||||
|
// these and use an external stylesheet then do this in your code:
|
||||||
|
// $.blockUI.defaults.css = {};
|
||||||
|
css: {
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
width: '30%',
|
||||||
|
top: '40%',
|
||||||
|
left: '35%',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#000',
|
||||||
|
border: '3px solid #aaa',
|
||||||
|
backgroundColor:'#fff',
|
||||||
|
cursor: 'wait'
|
||||||
|
},
|
||||||
|
|
||||||
|
// minimal style set used when themes are used
|
||||||
|
themedCSS: {
|
||||||
|
width: '30%',
|
||||||
|
top: '40%',
|
||||||
|
left: '35%'
|
||||||
|
},
|
||||||
|
|
||||||
|
// styles for the overlay
|
||||||
|
overlayCSS: {
|
||||||
|
backgroundColor: '#000',
|
||||||
|
opacity: 0.6,
|
||||||
|
cursor: 'wait'
|
||||||
|
},
|
||||||
|
|
||||||
|
// styles applied when using $.growlUI
|
||||||
|
growlCSS: {
|
||||||
|
width: '350px',
|
||||||
|
top: '10px',
|
||||||
|
left: '',
|
||||||
|
right: '10px',
|
||||||
|
border: 'none',
|
||||||
|
padding: '5px',
|
||||||
|
opacity: 0.6,
|
||||||
|
cursor: 'default',
|
||||||
|
color: '#fff',
|
||||||
|
backgroundColor: '#000',
|
||||||
|
'-webkit-border-radius': '10px',
|
||||||
|
'-moz-border-radius': '10px',
|
||||||
|
'border-radius': '10px'
|
||||||
|
},
|
||||||
|
|
||||||
|
// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
|
||||||
|
// (hat tip to Jorge H. N. de Vasconcelos)
|
||||||
|
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
|
||||||
|
|
||||||
|
// force usage of iframe in non-IE browsers (handy for blocking applets)
|
||||||
|
forceIframe: false,
|
||||||
|
|
||||||
|
// z-index for the blocking overlay
|
||||||
|
baseZ: 1000,
|
||||||
|
|
||||||
|
// set these to true to have the message automatically centered
|
||||||
|
centerX: true, // <-- only effects element blocking (page block controlled via css above)
|
||||||
|
centerY: true,
|
||||||
|
|
||||||
|
// allow body element to be stetched in ie6; this makes blocking look better
|
||||||
|
// on "short" pages. disable if you wish to prevent changes to the body height
|
||||||
|
allowBodyStretch: true,
|
||||||
|
|
||||||
|
// enable if you want key and mouse events to be disabled for content that is blocked
|
||||||
|
bindEvents: true,
|
||||||
|
|
||||||
|
// be default blockUI will supress tab navigation from leaving blocking content
|
||||||
|
// (if bindEvents is true)
|
||||||
|
constrainTabKey: true,
|
||||||
|
|
||||||
|
// fadeIn time in millis; set to 0 to disable fadeIn on block
|
||||||
|
fadeIn: 200,
|
||||||
|
|
||||||
|
// fadeOut time in millis; set to 0 to disable fadeOut on unblock
|
||||||
|
fadeOut: 400,
|
||||||
|
|
||||||
|
// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
|
||||||
|
timeout: 0,
|
||||||
|
|
||||||
|
// disable if you don't want to show the overlay
|
||||||
|
showOverlay: true,
|
||||||
|
|
||||||
|
// if true, focus will be placed in the first available input field when
|
||||||
|
// page blocking
|
||||||
|
focusInput: true,
|
||||||
|
|
||||||
|
// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
|
||||||
|
applyPlatformOpacityRules: true,
|
||||||
|
|
||||||
|
// callback method invoked when fadeIn has completed and blocking message is visible
|
||||||
|
onBlock: null,
|
||||||
|
|
||||||
|
// callback method invoked when unblocking has completed; the callback is
|
||||||
|
// passed the element that has been unblocked (which is the window object for page
|
||||||
|
// blocks) and the options that were passed to the unblock call:
|
||||||
|
// onUnblock(element, options)
|
||||||
|
onUnblock: null,
|
||||||
|
|
||||||
|
// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
|
||||||
|
quirksmodeOffsetHack: 4,
|
||||||
|
|
||||||
|
// class name of the message block
|
||||||
|
blockMsgClass: 'blockMsg'
|
||||||
|
};
|
||||||
|
|
||||||
|
// private data and functions follow...
|
||||||
|
|
||||||
|
var pageBlock = null;
|
||||||
|
var pageBlockEls = [];
|
||||||
|
|
||||||
|
function install(el, opts) {
|
||||||
|
var full = (el == window);
|
||||||
|
var msg = opts && opts.message !== undefined ? opts.message : undefined;
|
||||||
|
opts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||||
|
opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
|
||||||
|
var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
|
||||||
|
var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
|
||||||
|
msg = msg === undefined ? opts.message : msg;
|
||||||
|
|
||||||
|
// remove the current block (if there is one)
|
||||||
|
if (full && pageBlock)
|
||||||
|
remove(window, {fadeOut:0});
|
||||||
|
|
||||||
|
// if an existing element is being used as the blocking content then we capture
|
||||||
|
// its current place in the DOM (and current display style) so we can restore
|
||||||
|
// it when we unblock
|
||||||
|
if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
|
||||||
|
var node = msg.jquery ? msg[0] : msg;
|
||||||
|
var data = {};
|
||||||
|
$(el).data('blockUI.history', data);
|
||||||
|
data.el = node;
|
||||||
|
data.parent = node.parentNode;
|
||||||
|
data.display = node.style.display;
|
||||||
|
data.position = node.style.position;
|
||||||
|
if (data.parent)
|
||||||
|
data.parent.removeChild(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(el).data('blockUI.onUnblock', opts.onUnblock);
|
||||||
|
var z = opts.baseZ;
|
||||||
|
|
||||||
|
// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
|
||||||
|
// layer1 is the iframe layer which is used to supress bleed through of underlying content
|
||||||
|
// layer2 is the overlay layer which has opacity and a wait cursor (by default)
|
||||||
|
// layer3 is the message content that is displayed while blocking
|
||||||
|
|
||||||
|
var lyr1 = ($.browser.msie || opts.forceIframe)
|
||||||
|
? $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>')
|
||||||
|
: $('<div class="blockUI" style="display:none"></div>');
|
||||||
|
|
||||||
|
var lyr2 = opts.theme
|
||||||
|
? $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>')
|
||||||
|
: $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
|
||||||
|
|
||||||
|
var lyr3, s;
|
||||||
|
if (opts.theme && full) {
|
||||||
|
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">' +
|
||||||
|
'<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>' +
|
||||||
|
'<div class="ui-widget-content ui-dialog-content"></div>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
else if (opts.theme) {
|
||||||
|
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">' +
|
||||||
|
'<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>' +
|
||||||
|
'<div class="ui-widget-content ui-dialog-content"></div>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
else if (full) {
|
||||||
|
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
|
||||||
|
}
|
||||||
|
lyr3 = $(s);
|
||||||
|
|
||||||
|
// if we have a message, style it
|
||||||
|
if (msg) {
|
||||||
|
if (opts.theme) {
|
||||||
|
lyr3.css(themedCSS);
|
||||||
|
lyr3.addClass('ui-widget-content');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lyr3.css(css);
|
||||||
|
}
|
||||||
|
|
||||||
|
// style the overlay
|
||||||
|
if (!opts.theme && (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform))))
|
||||||
|
lyr2.css(opts.overlayCSS);
|
||||||
|
lyr2.css('position', full ? 'fixed' : 'absolute');
|
||||||
|
|
||||||
|
// make iframe layer transparent in IE
|
||||||
|
if ($.browser.msie || opts.forceIframe)
|
||||||
|
lyr1.css('opacity',0.0);
|
||||||
|
|
||||||
|
//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
|
||||||
|
var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
|
||||||
|
$.each(layers, function() {
|
||||||
|
this.appendTo($par);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opts.theme && opts.draggable && $.fn.draggable) {
|
||||||
|
lyr3.draggable({
|
||||||
|
handle: '.ui-dialog-titlebar',
|
||||||
|
cancel: 'li'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
|
||||||
|
var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
|
||||||
|
if (ie6 || expr) {
|
||||||
|
// give body 100% height
|
||||||
|
if (full && opts.allowBodyStretch && $.boxModel)
|
||||||
|
$('html,body').css('height','100%');
|
||||||
|
|
||||||
|
// fix ie6 issue when blocked element has a border width
|
||||||
|
if ((ie6 || !$.boxModel) && !full) {
|
||||||
|
var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
|
||||||
|
var fixT = t ? '(0 - '+t+')' : 0;
|
||||||
|
var fixL = l ? '(0 - '+l+')' : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulate fixed position
|
||||||
|
$.each([lyr1,lyr2,lyr3], function(i,o) {
|
||||||
|
var s = o[0].style;
|
||||||
|
s.position = 'absolute';
|
||||||
|
if (i < 2) {
|
||||||
|
full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
|
||||||
|
: s.setExpression('height','this.parentNode.offsetHeight + "px"');
|
||||||
|
full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
|
||||||
|
: s.setExpression('width','this.parentNode.offsetWidth + "px"');
|
||||||
|
if (fixL) s.setExpression('left', fixL);
|
||||||
|
if (fixT) s.setExpression('top', fixT);
|
||||||
|
}
|
||||||
|
else if (opts.centerY) {
|
||||||
|
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
|
||||||
|
s.marginTop = 0;
|
||||||
|
}
|
||||||
|
else if (!opts.centerY && full) {
|
||||||
|
var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
|
||||||
|
var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
|
||||||
|
s.setExpression('top',expression);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the message
|
||||||
|
if (msg) {
|
||||||
|
if (opts.theme)
|
||||||
|
lyr3.find('.ui-widget-content').append(msg);
|
||||||
|
else
|
||||||
|
lyr3.append(msg);
|
||||||
|
if (msg.jquery || msg.nodeType)
|
||||||
|
$(msg).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
|
||||||
|
lyr1.show(); // opacity is zero
|
||||||
|
if (opts.fadeIn) {
|
||||||
|
var cb = opts.onBlock ? opts.onBlock : noOp;
|
||||||
|
var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
|
||||||
|
var cb2 = msg ? cb : noOp;
|
||||||
|
if (opts.showOverlay)
|
||||||
|
lyr2._fadeIn(opts.fadeIn, cb1);
|
||||||
|
if (msg)
|
||||||
|
lyr3._fadeIn(opts.fadeIn, cb2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (opts.showOverlay)
|
||||||
|
lyr2.show();
|
||||||
|
if (msg)
|
||||||
|
lyr3.show();
|
||||||
|
if (opts.onBlock)
|
||||||
|
opts.onBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind key and mouse events
|
||||||
|
bind(1, el, opts);
|
||||||
|
|
||||||
|
if (full) {
|
||||||
|
pageBlock = lyr3[0];
|
||||||
|
pageBlockEls = $(':input:enabled:visible',pageBlock);
|
||||||
|
if (opts.focusInput)
|
||||||
|
setTimeout(focus, 20);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
center(lyr3[0], opts.centerX, opts.centerY);
|
||||||
|
|
||||||
|
if (opts.timeout) {
|
||||||
|
// auto-unblock
|
||||||
|
var to = setTimeout(function() {
|
||||||
|
full ? $.unblockUI(opts) : $(el).unblock(opts);
|
||||||
|
}, opts.timeout);
|
||||||
|
$(el).data('blockUI.timeout', to);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove the block
|
||||||
|
function remove(el, opts) {
|
||||||
|
var full = (el == window);
|
||||||
|
var $el = $(el);
|
||||||
|
var data = $el.data('blockUI.history');
|
||||||
|
var to = $el.data('blockUI.timeout');
|
||||||
|
if (to) {
|
||||||
|
clearTimeout(to);
|
||||||
|
$el.removeData('blockUI.timeout');
|
||||||
|
}
|
||||||
|
opts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||||
|
bind(0, el, opts); // unbind events
|
||||||
|
|
||||||
|
if (opts.onUnblock === null) {
|
||||||
|
opts.onUnblock = $el.data('blockUI.onUnblock');
|
||||||
|
$el.removeData('blockUI.onUnblock');
|
||||||
|
}
|
||||||
|
|
||||||
|
var els;
|
||||||
|
if (full) // crazy selector to handle odd field errors in ie6/7
|
||||||
|
els = $('body').children().filter('.blockUI').add('body > .blockUI');
|
||||||
|
else
|
||||||
|
els = $('.blockUI', el);
|
||||||
|
|
||||||
|
if (full)
|
||||||
|
pageBlock = pageBlockEls = null;
|
||||||
|
|
||||||
|
if (opts.fadeOut) {
|
||||||
|
els.fadeOut(opts.fadeOut);
|
||||||
|
setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reset(els, data, opts, el);
|
||||||
|
};
|
||||||
|
|
||||||
|
// move blocking element back into the DOM where it started
|
||||||
|
function reset(els,data,opts,el) {
|
||||||
|
els.each(function(i,o) {
|
||||||
|
// remove via DOM calls so we don't lose event handlers
|
||||||
|
if (this.parentNode)
|
||||||
|
this.parentNode.removeChild(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data && data.el) {
|
||||||
|
data.el.style.display = data.display;
|
||||||
|
data.el.style.position = data.position;
|
||||||
|
if (data.parent)
|
||||||
|
data.parent.appendChild(data.el);
|
||||||
|
$(el).removeData('blockUI.history');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof opts.onUnblock == 'function')
|
||||||
|
opts.onUnblock(el,opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
// bind/unbind the handler
|
||||||
|
function bind(b, el, opts) {
|
||||||
|
var full = el == window, $el = $(el);
|
||||||
|
|
||||||
|
// don't bother unbinding if there is nothing to unbind
|
||||||
|
if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
|
||||||
|
return;
|
||||||
|
if (!full)
|
||||||
|
$el.data('blockUI.isBlocked', b);
|
||||||
|
|
||||||
|
// don't bind events when overlay is not in use or if bindEvents is false
|
||||||
|
if (!opts.bindEvents || (b && !opts.showOverlay))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// bind anchors and inputs for mouse and key events
|
||||||
|
var events = 'mousedown mouseup keydown keypress';
|
||||||
|
b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);
|
||||||
|
|
||||||
|
// former impl...
|
||||||
|
// var $e = $('a,:input');
|
||||||
|
// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// event handler to suppress keyboard/mouse events when blocking
|
||||||
|
function handler(e) {
|
||||||
|
// allow tab navigation (conditionally)
|
||||||
|
if (e.keyCode && e.keyCode == 9) {
|
||||||
|
if (pageBlock && e.data.constrainTabKey) {
|
||||||
|
var els = pageBlockEls;
|
||||||
|
var fwd = !e.shiftKey && e.target === els[els.length-1];
|
||||||
|
var back = e.shiftKey && e.target === els[0];
|
||||||
|
if (fwd || back) {
|
||||||
|
setTimeout(function(){focus(back)},10);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var opts = e.data;
|
||||||
|
// allow events within the message content
|
||||||
|
if ($(e.target).parents('div.' + opts.blockMsgClass).length > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// allow events for content that is not being blocked
|
||||||
|
return $(e.target).parents().children().filter('div.blockUI').length == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
function focus(back) {
|
||||||
|
if (!pageBlockEls)
|
||||||
|
return;
|
||||||
|
var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
|
||||||
|
if (e)
|
||||||
|
e.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
function center(el, x, y) {
|
||||||
|
var p = el.parentNode, s = el.style;
|
||||||
|
var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
|
||||||
|
var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
|
||||||
|
if (x) s.left = l > 0 ? (l+'px') : '0';
|
||||||
|
if (y) s.top = t > 0 ? (t+'px') : '0';
|
||||||
|
};
|
||||||
|
|
||||||
|
function sz(el, p) {
|
||||||
|
return parseInt($.css(el,p))||0;
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
|
@ -0,0 +1,911 @@
|
||||||
|
/*!
|
||||||
|
* jQuery Form Plugin
|
||||||
|
* version: 2.83 (11-JUL-2011)
|
||||||
|
* @requires jQuery v1.3.2 or later
|
||||||
|
*
|
||||||
|
* Examples and documentation at: http://malsup.com/jquery/form/
|
||||||
|
* Dual licensed under the MIT and GPL licenses:
|
||||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*/
|
||||||
|
;(function($) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Usage Note:
|
||||||
|
-----------
|
||||||
|
Do not use both ajaxSubmit and ajaxForm on the same form. These
|
||||||
|
functions are intended to be exclusive. Use ajaxSubmit if you want
|
||||||
|
to bind your own submit handler to the form. For example,
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#myForm').bind('submit', function(e) {
|
||||||
|
e.preventDefault(); // <-- important
|
||||||
|
$(this).ajaxSubmit({
|
||||||
|
target: '#output'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Use ajaxForm when you want the plugin to manage all the event binding
|
||||||
|
for you. For example,
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#myForm').ajaxForm({
|
||||||
|
target: '#output'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
When using ajaxForm, the ajaxSubmit function will be invoked for you
|
||||||
|
at the appropriate time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ajaxSubmit() provides a mechanism for immediately submitting
|
||||||
|
* an HTML form using AJAX.
|
||||||
|
*/
|
||||||
|
$.fn.ajaxSubmit = function(options) {
|
||||||
|
// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
|
||||||
|
if (!this.length) {
|
||||||
|
log('ajaxSubmit: skipping submit process - no element selected');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var method, action, url, $form = this;
|
||||||
|
|
||||||
|
if (typeof options == 'function') {
|
||||||
|
options = { success: options };
|
||||||
|
}
|
||||||
|
|
||||||
|
method = this.attr('method');
|
||||||
|
action = this.attr('action');
|
||||||
|
url = (typeof action === 'string') ? $.trim(action) : '';
|
||||||
|
url = url || window.location.href || '';
|
||||||
|
if (url) {
|
||||||
|
// clean url (don't include hash vaue)
|
||||||
|
url = (url.match(/^([^#]+)/)||[])[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
options = $.extend(true, {
|
||||||
|
url: url,
|
||||||
|
success: $.ajaxSettings.success,
|
||||||
|
type: method || 'GET',
|
||||||
|
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
// hook for manipulating the form data before it is extracted;
|
||||||
|
// convenient for use with rich editors like tinyMCE or FCKEditor
|
||||||
|
var veto = {};
|
||||||
|
this.trigger('form-pre-serialize', [this, options, veto]);
|
||||||
|
if (veto.veto) {
|
||||||
|
log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// provide opportunity to alter form data before it is serialized
|
||||||
|
if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
|
||||||
|
log('ajaxSubmit: submit aborted via beforeSerialize callback');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var n,v,a = this.formToArray(options.semantic);
|
||||||
|
if (options.data) {
|
||||||
|
options.extraData = options.data;
|
||||||
|
for (n in options.data) {
|
||||||
|
if(options.data[n] instanceof Array) {
|
||||||
|
for (var k in options.data[n]) {
|
||||||
|
a.push( { name: n, value: options.data[n][k] } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = options.data[n];
|
||||||
|
v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
|
||||||
|
a.push( { name: n, value: v } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// give pre-submit callback an opportunity to abort the submit
|
||||||
|
if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
|
||||||
|
log('ajaxSubmit: submit aborted via beforeSubmit callback');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fire vetoable 'validate' event
|
||||||
|
this.trigger('form-submit-validate', [a, this, options, veto]);
|
||||||
|
if (veto.veto) {
|
||||||
|
log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var q = $.param(a);
|
||||||
|
|
||||||
|
if (options.type.toUpperCase() == 'GET') {
|
||||||
|
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
|
||||||
|
options.data = null; // data is null for 'get'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
options.data = q; // data is the query string for 'post'
|
||||||
|
}
|
||||||
|
|
||||||
|
var callbacks = [];
|
||||||
|
if (options.resetForm) {
|
||||||
|
callbacks.push(function() { $form.resetForm(); });
|
||||||
|
}
|
||||||
|
if (options.clearForm) {
|
||||||
|
callbacks.push(function() { $form.clearForm(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform a load on the target only if dataType is not provided
|
||||||
|
if (!options.dataType && options.target) {
|
||||||
|
var oldSuccess = options.success || function(){};
|
||||||
|
callbacks.push(function(data) {
|
||||||
|
var fn = options.replaceTarget ? 'replaceWith' : 'html';
|
||||||
|
$(options.target)[fn](data).each(oldSuccess, arguments);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (options.success) {
|
||||||
|
callbacks.push(options.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
|
||||||
|
var context = options.context || options; // jQuery 1.4+ supports scope context
|
||||||
|
for (var i=0, max=callbacks.length; i < max; i++) {
|
||||||
|
callbacks[i].apply(context, [data, status, xhr || $form, $form]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// are there files to upload?
|
||||||
|
var fileInputs = $('input:file', this).length > 0;
|
||||||
|
var mp = 'multipart/form-data';
|
||||||
|
var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
|
||||||
|
|
||||||
|
// options.iframe allows user to force iframe mode
|
||||||
|
// 06-NOV-09: now defaulting to iframe mode if file input is detected
|
||||||
|
if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
|
||||||
|
// hack to fix Safari hang (thanks to Tim Molendijk for this)
|
||||||
|
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
|
||||||
|
if (options.closeKeepAlive) {
|
||||||
|
$.get(options.closeKeepAlive, function() { fileUpload(a); });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fileUpload(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// IE7 massage (see issue 57)
|
||||||
|
if ($.browser.msie && method == 'get') {
|
||||||
|
var ieMeth = $form[0].getAttribute('method');
|
||||||
|
if (typeof ieMeth === 'string')
|
||||||
|
options.type = ieMeth;
|
||||||
|
}
|
||||||
|
$.ajax(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fire 'notify' event
|
||||||
|
this.trigger('form-submit-notify', [this, options]);
|
||||||
|
return this;
|
||||||
|
|
||||||
|
|
||||||
|
// private function for handling file uploads (hat tip to YAHOO!)
|
||||||
|
function fileUpload(a) {
|
||||||
|
var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
|
||||||
|
var useProp = !!$.fn.prop;
|
||||||
|
|
||||||
|
if (a) {
|
||||||
|
// ensure that every serialized input is still enabled
|
||||||
|
for (i=0; i < a.length; i++) {
|
||||||
|
el = $(form[a[i].name]);
|
||||||
|
el[ useProp ? 'prop' : 'attr' ]('disabled', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(':input[name=submit],:input[id=submit]', form).length) {
|
||||||
|
// if there is an input with a name or id of 'submit' then we won't be
|
||||||
|
// able to invoke the submit fn on the form (at least not x-browser)
|
||||||
|
alert('Error: Form elements must not have name or id of "submit".');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = $.extend(true, {}, $.ajaxSettings, options);
|
||||||
|
s.context = s.context || s;
|
||||||
|
id = 'jqFormIO' + (new Date().getTime());
|
||||||
|
if (s.iframeTarget) {
|
||||||
|
$io = $(s.iframeTarget);
|
||||||
|
n = $io.attr('name');
|
||||||
|
if (n == null)
|
||||||
|
$io.attr('name', id);
|
||||||
|
else
|
||||||
|
id = n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
|
||||||
|
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
||||||
|
}
|
||||||
|
io = $io[0];
|
||||||
|
|
||||||
|
|
||||||
|
xhr = { // mock object
|
||||||
|
aborted: 0,
|
||||||
|
responseText: null,
|
||||||
|
responseXML: null,
|
||||||
|
status: 0,
|
||||||
|
statusText: 'n/a',
|
||||||
|
getAllResponseHeaders: function() {},
|
||||||
|
getResponseHeader: function() {},
|
||||||
|
setRequestHeader: function() {},
|
||||||
|
abort: function(status) {
|
||||||
|
var e = (status === 'timeout' ? 'timeout' : 'aborted');
|
||||||
|
log('aborting upload... ' + e);
|
||||||
|
this.aborted = 1;
|
||||||
|
$io.attr('src', s.iframeSrc); // abort op in progress
|
||||||
|
xhr.error = e;
|
||||||
|
s.error && s.error.call(s.context, xhr, e, status);
|
||||||
|
g && $.event.trigger("ajaxError", [xhr, s, e]);
|
||||||
|
s.complete && s.complete.call(s.context, xhr, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
g = s.global;
|
||||||
|
// trigger ajax global events so that activity/block indicators work like normal
|
||||||
|
if (g && ! $.active++) {
|
||||||
|
$.event.trigger("ajaxStart");
|
||||||
|
}
|
||||||
|
if (g) {
|
||||||
|
$.event.trigger("ajaxSend", [xhr, s]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
|
||||||
|
if (s.global) {
|
||||||
|
$.active--;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (xhr.aborted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add submitting element to data if we know it
|
||||||
|
sub = form.clk;
|
||||||
|
if (sub) {
|
||||||
|
n = sub.name;
|
||||||
|
if (n && !sub.disabled) {
|
||||||
|
s.extraData = s.extraData || {};
|
||||||
|
s.extraData[n] = sub.value;
|
||||||
|
if (sub.type == "image") {
|
||||||
|
s.extraData[n+'.x'] = form.clk_x;
|
||||||
|
s.extraData[n+'.y'] = form.clk_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var CLIENT_TIMEOUT_ABORT = 1;
|
||||||
|
var SERVER_ABORT = 2;
|
||||||
|
|
||||||
|
function getDoc(frame) {
|
||||||
|
var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// take a breath so that pending repaints get some cpu time before the upload starts
|
||||||
|
function doSubmit() {
|
||||||
|
// make sure form attrs are set
|
||||||
|
var t = $form.attr('target'), a = $form.attr('action');
|
||||||
|
|
||||||
|
// update form attrs in IE friendly way
|
||||||
|
form.setAttribute('target',id);
|
||||||
|
if (!method) {
|
||||||
|
form.setAttribute('method', 'POST');
|
||||||
|
}
|
||||||
|
if (a != s.url) {
|
||||||
|
form.setAttribute('action', s.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ie borks in some cases when setting encoding
|
||||||
|
if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
|
||||||
|
$form.attr({
|
||||||
|
encoding: 'multipart/form-data',
|
||||||
|
enctype: 'multipart/form-data'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// support timout
|
||||||
|
if (s.timeout) {
|
||||||
|
timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for server aborts
|
||||||
|
function checkState() {
|
||||||
|
try {
|
||||||
|
var state = getDoc(io).readyState;
|
||||||
|
log('state = ' + state);
|
||||||
|
if (state.toLowerCase() == 'uninitialized')
|
||||||
|
setTimeout(checkState,50);
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
log('Server abort: ' , e, ' (', e.name, ')');
|
||||||
|
cb(SERVER_ABORT);
|
||||||
|
timeoutHandle && clearTimeout(timeoutHandle);
|
||||||
|
timeoutHandle = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add "extra" data to form if provided in options
|
||||||
|
var extraInputs = [];
|
||||||
|
try {
|
||||||
|
if (s.extraData) {
|
||||||
|
for (var n in s.extraData) {
|
||||||
|
extraInputs.push(
|
||||||
|
$('<input type="hidden" name="'+n+'" />').attr('value',s.extraData[n])
|
||||||
|
.appendTo(form)[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.iframeTarget) {
|
||||||
|
// add iframe to doc and submit the form
|
||||||
|
$io.appendTo('body');
|
||||||
|
io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
|
||||||
|
}
|
||||||
|
setTimeout(checkState,15);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// reset attrs and remove "extra" input elements
|
||||||
|
form.setAttribute('action',a);
|
||||||
|
if(t) {
|
||||||
|
form.setAttribute('target', t);
|
||||||
|
} else {
|
||||||
|
$form.removeAttr('target');
|
||||||
|
}
|
||||||
|
$(extraInputs).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.forceSync) {
|
||||||
|
doSubmit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setTimeout(doSubmit, 10); // this lets dom updates render
|
||||||
|
}
|
||||||
|
|
||||||
|
var data, doc, domCheckCount = 50, callbackProcessed;
|
||||||
|
|
||||||
|
function cb(e) {
|
||||||
|
if (xhr.aborted || callbackProcessed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
doc = getDoc(io);
|
||||||
|
}
|
||||||
|
catch(ex) {
|
||||||
|
log('cannot access response document: ', ex);
|
||||||
|
e = SERVER_ABORT;
|
||||||
|
}
|
||||||
|
if (e === CLIENT_TIMEOUT_ABORT && xhr) {
|
||||||
|
xhr.abort('timeout');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (e == SERVER_ABORT && xhr) {
|
||||||
|
xhr.abort('server abort');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doc || doc.location.href == s.iframeSrc) {
|
||||||
|
// response not received yet
|
||||||
|
if (!timedOut)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
|
||||||
|
|
||||||
|
var status = 'success', errMsg;
|
||||||
|
try {
|
||||||
|
if (timedOut) {
|
||||||
|
throw 'timeout';
|
||||||
|
}
|
||||||
|
|
||||||
|
var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
|
||||||
|
log('isXml='+isXml);
|
||||||
|
if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
|
||||||
|
if (--domCheckCount) {
|
||||||
|
// in some browsers (Opera) the iframe DOM is not always traversable when
|
||||||
|
// the onload callback fires, so we loop a bit to accommodate
|
||||||
|
log('requeing onLoad callback, DOM not available');
|
||||||
|
setTimeout(cb, 250);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// let this fall through because server response could be an empty document
|
||||||
|
//log('Could not access iframe DOM after mutiple tries.');
|
||||||
|
//throw 'DOMException: not available';
|
||||||
|
}
|
||||||
|
|
||||||
|
//log('response detected');
|
||||||
|
var docRoot = doc.body ? doc.body : doc.documentElement;
|
||||||
|
xhr.responseText = docRoot ? docRoot.innerHTML : null;
|
||||||
|
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
|
||||||
|
if (isXml)
|
||||||
|
s.dataType = 'xml';
|
||||||
|
xhr.getResponseHeader = function(header){
|
||||||
|
var headers = {'content-type': s.dataType};
|
||||||
|
return headers[header];
|
||||||
|
};
|
||||||
|
// support for XHR 'status' & 'statusText' emulation :
|
||||||
|
if (docRoot) {
|
||||||
|
xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
|
||||||
|
xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dt = s.dataType || '';
|
||||||
|
var scr = /(json|script|text)/.test(dt.toLowerCase());
|
||||||
|
if (scr || s.textarea) {
|
||||||
|
// see if user embedded response in textarea
|
||||||
|
var ta = doc.getElementsByTagName('textarea')[0];
|
||||||
|
if (ta) {
|
||||||
|
xhr.responseText = ta.value;
|
||||||
|
// support for XHR 'status' & 'statusText' emulation :
|
||||||
|
xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
|
||||||
|
xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
|
||||||
|
}
|
||||||
|
else if (scr) {
|
||||||
|
// account for browsers injecting pre around json response
|
||||||
|
var pre = doc.getElementsByTagName('pre')[0];
|
||||||
|
var b = doc.getElementsByTagName('body')[0];
|
||||||
|
if (pre) {
|
||||||
|
xhr.responseText = pre.textContent ? pre.textContent : pre.innerHTML;
|
||||||
|
}
|
||||||
|
else if (b) {
|
||||||
|
xhr.responseText = b.innerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
|
||||||
|
xhr.responseXML = toXml(xhr.responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = httpData(xhr, s.dataType, s);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
status = 'parsererror';
|
||||||
|
xhr.error = errMsg = (e || status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
log('error caught: ',e);
|
||||||
|
status = 'error';
|
||||||
|
xhr.error = errMsg = (e || status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xhr.aborted) {
|
||||||
|
log('upload aborted');
|
||||||
|
status = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xhr.status) { // we've set xhr.status
|
||||||
|
status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
|
||||||
|
if (status === 'success') {
|
||||||
|
s.success && s.success.call(s.context, data, 'success', xhr);
|
||||||
|
g && $.event.trigger("ajaxSuccess", [xhr, s]);
|
||||||
|
}
|
||||||
|
else if (status) {
|
||||||
|
if (errMsg == undefined)
|
||||||
|
errMsg = xhr.statusText;
|
||||||
|
s.error && s.error.call(s.context, xhr, status, errMsg);
|
||||||
|
g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g && $.event.trigger("ajaxComplete", [xhr, s]);
|
||||||
|
|
||||||
|
if (g && ! --$.active) {
|
||||||
|
$.event.trigger("ajaxStop");
|
||||||
|
}
|
||||||
|
|
||||||
|
s.complete && s.complete.call(s.context, xhr, status);
|
||||||
|
|
||||||
|
callbackProcessed = true;
|
||||||
|
if (s.timeout)
|
||||||
|
clearTimeout(timeoutHandle);
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
setTimeout(function() {
|
||||||
|
if (!s.iframeTarget)
|
||||||
|
$io.remove();
|
||||||
|
xhr.responseXML = null;
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
|
||||||
|
if (window.ActiveXObject) {
|
||||||
|
doc = new ActiveXObject('Microsoft.XMLDOM');
|
||||||
|
doc.async = 'false';
|
||||||
|
doc.loadXML(s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
||||||
|
}
|
||||||
|
return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
|
||||||
|
};
|
||||||
|
var parseJSON = $.parseJSON || function(s) {
|
||||||
|
return window['eval']('(' + s + ')');
|
||||||
|
};
|
||||||
|
|
||||||
|
var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
|
||||||
|
|
||||||
|
var ct = xhr.getResponseHeader('content-type') || '',
|
||||||
|
xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
|
||||||
|
data = xml ? xhr.responseXML : xhr.responseText;
|
||||||
|
|
||||||
|
if (xml && data.documentElement.nodeName === 'parsererror') {
|
||||||
|
$.error && $.error('parsererror');
|
||||||
|
}
|
||||||
|
if (s && s.dataFilter) {
|
||||||
|
data = s.dataFilter(data, type);
|
||||||
|
}
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
if (type === 'json' || !type && ct.indexOf('json') >= 0) {
|
||||||
|
data = parseJSON(data);
|
||||||
|
} else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
|
||||||
|
$.globalEval(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ajaxForm() provides a mechanism for fully automating form submission.
|
||||||
|
*
|
||||||
|
* The advantages of using this method instead of ajaxSubmit() are:
|
||||||
|
*
|
||||||
|
* 1: This method will include coordinates for <input type="image" /> elements (if the element
|
||||||
|
* is used to submit the form).
|
||||||
|
* 2. This method will include the submit element's name/value data (for the element that was
|
||||||
|
* used to submit the form).
|
||||||
|
* 3. This method binds the submit() method to the form for you.
|
||||||
|
*
|
||||||
|
* The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
|
||||||
|
* passes the options argument along after properly binding events for submit elements and
|
||||||
|
* the form itself.
|
||||||
|
*/
|
||||||
|
$.fn.ajaxForm = function(options) {
|
||||||
|
// in jQuery 1.3+ we can fix mistakes with the ready state
|
||||||
|
if (this.length === 0) {
|
||||||
|
var o = { s: this.selector, c: this.context };
|
||||||
|
if (!$.isReady && o.s) {
|
||||||
|
log('DOM not ready, queuing ajaxForm');
|
||||||
|
$(function() {
|
||||||
|
$(o.s,o.c).ajaxForm(options);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
|
||||||
|
log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
|
||||||
|
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
|
||||||
|
e.preventDefault();
|
||||||
|
$(this).ajaxSubmit(options);
|
||||||
|
}
|
||||||
|
}).bind('click.form-plugin', function(e) {
|
||||||
|
var target = e.target;
|
||||||
|
var $el = $(target);
|
||||||
|
if (!($el.is(":submit,input:image"))) {
|
||||||
|
// is this a child element of the submit el? (ex: a span within a button)
|
||||||
|
var t = $el.closest(':submit');
|
||||||
|
if (t.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
target = t[0];
|
||||||
|
}
|
||||||
|
var form = this;
|
||||||
|
form.clk = target;
|
||||||
|
if (target.type == 'image') {
|
||||||
|
if (e.offsetX != undefined) {
|
||||||
|
form.clk_x = e.offsetX;
|
||||||
|
form.clk_y = e.offsetY;
|
||||||
|
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
|
||||||
|
var offset = $el.offset();
|
||||||
|
form.clk_x = e.pageX - offset.left;
|
||||||
|
form.clk_y = e.pageY - offset.top;
|
||||||
|
} else {
|
||||||
|
form.clk_x = e.pageX - target.offsetLeft;
|
||||||
|
form.clk_y = e.pageY - target.offsetTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear form vars
|
||||||
|
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
||||||
|
$.fn.ajaxFormUnbind = function() {
|
||||||
|
return this.unbind('submit.form-plugin click.form-plugin');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* formToArray() gathers form element data into an array of objects that can
|
||||||
|
* be passed to any of the following ajax functions: $.get, $.post, or load.
|
||||||
|
* Each object in the array has both a 'name' and 'value' property. An example of
|
||||||
|
* an array for a simple login form might be:
|
||||||
|
*
|
||||||
|
* [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
|
||||||
|
*
|
||||||
|
* It is this array that is passed to pre-submit callback functions provided to the
|
||||||
|
* ajaxSubmit() and ajaxForm() methods.
|
||||||
|
*/
|
||||||
|
$.fn.formToArray = function(semantic) {
|
||||||
|
var a = [];
|
||||||
|
if (this.length === 0) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
var form = this[0];
|
||||||
|
var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
||||||
|
if (!els) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i,j,n,v,el,max,jmax;
|
||||||
|
for(i=0, max=els.length; i < max; i++) {
|
||||||
|
el = els[i];
|
||||||
|
n = el.name;
|
||||||
|
if (!n) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (semantic && form.clk && el.type == "image") {
|
||||||
|
// handle image inputs on the fly when semantic == true
|
||||||
|
if(!el.disabled && form.clk == el) {
|
||||||
|
a.push({name: n, value: $(el).val()});
|
||||||
|
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = $.fieldValue(el, true);
|
||||||
|
if (v && v.constructor == Array) {
|
||||||
|
for(j=0, jmax=v.length; j < jmax; j++) {
|
||||||
|
a.push({name: n, value: v[j]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (v !== null && typeof v != 'undefined') {
|
||||||
|
a.push({name: n, value: v});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!semantic && form.clk) {
|
||||||
|
// input type=='image' are not found in elements array! handle it here
|
||||||
|
var $input = $(form.clk), input = $input[0];
|
||||||
|
n = input.name;
|
||||||
|
if (n && !input.disabled && input.type == 'image') {
|
||||||
|
a.push({name: n, value: $input.val()});
|
||||||
|
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes form data into a 'submittable' string. This method will return a string
|
||||||
|
* in the format: name1=value1&name2=value2
|
||||||
|
*/
|
||||||
|
$.fn.formSerialize = function(semantic) {
|
||||||
|
//hand off to jQuery.param for proper encoding
|
||||||
|
return $.param(this.formToArray(semantic));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes all field elements in the jQuery object into a query string.
|
||||||
|
* This method will return a string in the format: name1=value1&name2=value2
|
||||||
|
*/
|
||||||
|
$.fn.fieldSerialize = function(successful) {
|
||||||
|
var a = [];
|
||||||
|
this.each(function() {
|
||||||
|
var n = this.name;
|
||||||
|
if (!n) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var v = $.fieldValue(this, successful);
|
||||||
|
if (v && v.constructor == Array) {
|
||||||
|
for (var i=0,max=v.length; i < max; i++) {
|
||||||
|
a.push({name: n, value: v[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (v !== null && typeof v != 'undefined') {
|
||||||
|
a.push({name: this.name, value: v});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//hand off to jQuery.param for proper encoding
|
||||||
|
return $.param(a);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value(s) of the element in the matched set. For example, consider the following form:
|
||||||
|
*
|
||||||
|
* <form><fieldset>
|
||||||
|
* <input name="A" type="text" />
|
||||||
|
* <input name="A" type="text" />
|
||||||
|
* <input name="B" type="checkbox" value="B1" />
|
||||||
|
* <input name="B" type="checkbox" value="B2"/>
|
||||||
|
* <input name="C" type="radio" value="C1" />
|
||||||
|
* <input name="C" type="radio" value="C2" />
|
||||||
|
* </fieldset></form>
|
||||||
|
*
|
||||||
|
* var v = $(':text').fieldValue();
|
||||||
|
* // if no values are entered into the text inputs
|
||||||
|
* v == ['','']
|
||||||
|
* // if values entered into the text inputs are 'foo' and 'bar'
|
||||||
|
* v == ['foo','bar']
|
||||||
|
*
|
||||||
|
* var v = $(':checkbox').fieldValue();
|
||||||
|
* // if neither checkbox is checked
|
||||||
|
* v === undefined
|
||||||
|
* // if both checkboxes are checked
|
||||||
|
* v == ['B1', 'B2']
|
||||||
|
*
|
||||||
|
* var v = $(':radio').fieldValue();
|
||||||
|
* // if neither radio is checked
|
||||||
|
* v === undefined
|
||||||
|
* // if first radio is checked
|
||||||
|
* v == ['C1']
|
||||||
|
*
|
||||||
|
* The successful argument controls whether or not the field element must be 'successful'
|
||||||
|
* (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
|
||||||
|
* The default value of the successful argument is true. If this value is false the value(s)
|
||||||
|
* for each element is returned.
|
||||||
|
*
|
||||||
|
* Note: This method *always* returns an array. If no valid value can be determined the
|
||||||
|
* array will be empty, otherwise it will contain one or more values.
|
||||||
|
*/
|
||||||
|
$.fn.fieldValue = function(successful) {
|
||||||
|
for (var val=[], i=0, max=this.length; i < max; i++) {
|
||||||
|
var el = this[i];
|
||||||
|
var v = $.fieldValue(el, successful);
|
||||||
|
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
v.constructor == Array ? $.merge(val, v) : val.push(v);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the field element.
|
||||||
|
*/
|
||||||
|
$.fieldValue = function(el, successful) {
|
||||||
|
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
||||||
|
if (successful === undefined) {
|
||||||
|
successful = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
||||||
|
(t == 'checkbox' || t == 'radio') && !el.checked ||
|
||||||
|
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
||||||
|
tag == 'select' && el.selectedIndex == -1)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == 'select') {
|
||||||
|
var index = el.selectedIndex;
|
||||||
|
if (index < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var a = [], ops = el.options;
|
||||||
|
var one = (t == 'select-one');
|
||||||
|
var max = (one ? index+1 : ops.length);
|
||||||
|
for(var i=(one ? index : 0); i < max; i++) {
|
||||||
|
var op = ops[i];
|
||||||
|
if (op.selected) {
|
||||||
|
var v = op.value;
|
||||||
|
if (!v) { // extra pain for IE...
|
||||||
|
v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
|
||||||
|
}
|
||||||
|
if (one) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
a.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return $(el).val();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the form data. Takes the following actions on the form's input fields:
|
||||||
|
* - input text fields will have their 'value' property set to the empty string
|
||||||
|
* - select elements will have their 'selectedIndex' property set to -1
|
||||||
|
* - checkbox and radio inputs will have their 'checked' property set to false
|
||||||
|
* - inputs of type submit, button, reset, and hidden will *not* be effected
|
||||||
|
* - button elements will *not* be effected
|
||||||
|
*/
|
||||||
|
$.fn.clearForm = function() {
|
||||||
|
return this.each(function() {
|
||||||
|
$('input,select,textarea', this).clearFields();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the selected form elements.
|
||||||
|
*/
|
||||||
|
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||||
|
var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
|
||||||
|
return this.each(function() {
|
||||||
|
var t = this.type, tag = this.tagName.toLowerCase();
|
||||||
|
if (re.test(t) || tag == 'textarea') {
|
||||||
|
this.value = '';
|
||||||
|
}
|
||||||
|
else if (t == 'checkbox' || t == 'radio') {
|
||||||
|
this.checked = false;
|
||||||
|
}
|
||||||
|
else if (tag == 'select') {
|
||||||
|
this.selectedIndex = -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the form data. Causes all form elements to be reset to their original value.
|
||||||
|
*/
|
||||||
|
$.fn.resetForm = function() {
|
||||||
|
return this.each(function() {
|
||||||
|
// guard against an input with the name of 'reset'
|
||||||
|
// note that IE reports the reset function as an 'object'
|
||||||
|
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables any matching elements.
|
||||||
|
*/
|
||||||
|
$.fn.enable = function(b) {
|
||||||
|
if (b === undefined) {
|
||||||
|
b = true;
|
||||||
|
}
|
||||||
|
return this.each(function() {
|
||||||
|
this.disabled = !b;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks/unchecks any matching checkboxes or radio buttons and
|
||||||
|
* selects/deselects and matching option elements.
|
||||||
|
*/
|
||||||
|
$.fn.selected = function(select) {
|
||||||
|
if (select === undefined) {
|
||||||
|
select = true;
|
||||||
|
}
|
||||||
|
return this.each(function() {
|
||||||
|
var t = this.type;
|
||||||
|
if (t == 'checkbox' || t == 'radio') {
|
||||||
|
this.checked = select;
|
||||||
|
}
|
||||||
|
else if (this.tagName.toLowerCase() == 'option') {
|
||||||
|
var $sel = $(this).parent('select');
|
||||||
|
if (select && $sel[0] && $sel[0].type == 'select-one') {
|
||||||
|
// deselect all other options
|
||||||
|
$sel.find('option').selected(false);
|
||||||
|
}
|
||||||
|
this.selected = select;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// helper fn for console logging
|
||||||
|
function log() {
|
||||||
|
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
|
||||||
|
if (window.console && window.console.log) {
|
||||||
|
window.console.log(msg);
|
||||||
|
}
|
||||||
|
else if (window.opera && window.opera.postError) {
|
||||||
|
window.opera.postError(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
File diff suppressed because it is too large
Load Diff
|
@ -30,9 +30,13 @@ body.openerp {
|
||||||
.openerp .oe-number {
|
.openerp .oe-number {
|
||||||
text-align: right !important;
|
text-align: right !important;
|
||||||
}
|
}
|
||||||
|
.openerp .oe_hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* STATES */
|
/* STATES */
|
||||||
.openerp .on_logged {
|
.openerp .on_logged,
|
||||||
|
.openerp .db_options_row {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,10 +139,84 @@ body.openerp {
|
||||||
}
|
}
|
||||||
.openerp.login-mode .menu,
|
.openerp.login-mode .menu,
|
||||||
.openerp.login-mode .secondary_menu,
|
.openerp.login-mode .secondary_menu,
|
||||||
.openerp.login-mode .oe-application {
|
.openerp.login-mode .oe-application,
|
||||||
|
.openerp.login-mode .db_options_row {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Database */
|
||||||
|
.openerp.database_block .db_options_row {
|
||||||
|
height: 100%;
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openerp.database_block .menu,
|
||||||
|
.openerp.database_block .secondary_menu,
|
||||||
|
.openerp.database_block .oe-application,
|
||||||
|
.openerp.database_block .login-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db_container {
|
||||||
|
width: 15%;
|
||||||
|
background: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.db_options li {
|
||||||
|
padding: 5px 0 10px 5px;
|
||||||
|
background: #949292; /* Old browsers */
|
||||||
|
background: -moz-linear-gradient(top, #949292 30%, #6d6b6b 95%, #282828 100%); /* FF3.6+ */
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(30%,#949292), color-stop(95%,#6d6b6b), color-stop(100%,#282828)); /* Chrome,Safari4+ */
|
||||||
|
background: -webkit-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Chrome10+,Safari5.1+ */
|
||||||
|
background: -o-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Opera11.10+ */
|
||||||
|
background: -ms-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* IE10+ */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */
|
||||||
|
background: linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* W3C */
|
||||||
|
/* for ie9 */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */
|
||||||
|
border: none;
|
||||||
|
/* overriding jquery ui */
|
||||||
|
-moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px;
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin: 1px;
|
||||||
|
color: #EEEEEE;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 196px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db_option_table {
|
||||||
|
border: 1px solid #5A5858;
|
||||||
|
padding: 5px;
|
||||||
|
-moz-border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.db_option_table input.required {
|
||||||
|
background-color: #D2D2FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db_option_table input[type="text"], input[type="password"], select {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option_string {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.error {
|
||||||
|
float: none;
|
||||||
|
color: red;
|
||||||
|
padding-left: .5em;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
/* Main*/
|
/* Main*/
|
||||||
.openerp .main_table {
|
.openerp .main_table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -158,14 +236,14 @@ body.openerp {
|
||||||
|
|
||||||
.openerp .menu {
|
.openerp .menu {
|
||||||
height: 34px;
|
height: 34px;
|
||||||
background: #cc4e45; /* Old browsers */
|
background: #cc4e45; /* Old browsers */
|
||||||
background: -moz-linear-gradient(top, #cc4e45 0%, #b52d20 8%, #7a211a 100%); /* FF3.6+ */
|
background: -moz-linear-gradient(top, #cc4e45 0%, #b52d20 8%, #7a211a 100%); /* FF3.6+ */
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cc4e45), color-stop(8%,#b52d20), color-stop(100%,#7a211a)); /* Chrome,Safari4+ */
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cc4e45), color-stop(8%,#b52d20), color-stop(100%,#7a211a)); /* Chrome,Safari4+ */
|
||||||
background: -webkit-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Chrome10+,Safari5.1+ */
|
background: -webkit-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Chrome10+,Safari5.1+ */
|
||||||
background: -o-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Opera11.10+ */
|
background: -o-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Opera11.10+ */
|
||||||
background: -ms-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* IE10+ */
|
background: -ms-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* IE10+ */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#CC4E45', endColorstr='#7A211A',GradientType=0 ); /* IE6-9 */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#CC4E45', endColorstr='#7A211A',GradientType=0 ); /* IE6-9 */
|
||||||
background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */
|
background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */
|
||||||
}
|
}
|
||||||
.openerp .menu td {
|
.openerp .menu td {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -178,14 +256,14 @@ background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */
|
||||||
margin: 3px 2px;
|
margin: 3px 2px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
|
||||||
background: #bd5e54; /* Old browsers */
|
background: #bd5e54; /* Old browsers */
|
||||||
background: -moz-linear-gradient(top, #bd5e54 0%, #90322a 60%); /* FF3.6+ */
|
background: -moz-linear-gradient(top, #bd5e54 0%, #90322a 60%); /* FF3.6+ */
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bd5e54), color-stop(60%,#90322a)); /* Chrome,Safari4+ */
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bd5e54), color-stop(60%,#90322a)); /* Chrome,Safari4+ */
|
||||||
background: -webkit-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Chrome10+,Safari5.1+ */
|
background: -webkit-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Chrome10+,Safari5.1+ */
|
||||||
background: -o-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Opera11.10+ */
|
background: -o-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Opera11.10+ */
|
||||||
background: -ms-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* IE10+ */
|
background: -ms-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* IE10+ */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */
|
||||||
background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
|
background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
|
||||||
|
|
||||||
border: 1px solid #6E2A24;
|
border: 1px solid #6E2A24;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
@ -205,16 +283,16 @@ background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
|
||||||
.openerp .menu a:hover,
|
.openerp .menu a:hover,
|
||||||
.openerp .menu a:focus,
|
.openerp .menu a:focus,
|
||||||
.openerp .menu a.active {
|
.openerp .menu a.active {
|
||||||
background: #c6c6c6; /* Old browsers */
|
background: #c6c6c6; /* Old browsers */
|
||||||
background: -moz-linear-gradient(top, #c6c6c6 0%, #5c5c5c 7%, #969595 86%); /* FF3.6+ */
|
background: -moz-linear-gradient(top, #c6c6c6 0%, #5c5c5c 7%, #969595 86%); /* FF3.6+ */
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#c6c6c6), color-stop(7%,#5c5c5c), color-stop(86%,#969595)); /* Chrome,Safari4+ */
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#c6c6c6), color-stop(7%,#5c5c5c), color-stop(86%,#969595)); /* Chrome,Safari4+ */
|
||||||
background: -webkit-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Chrome10+,Safari5.1+ */
|
background: -webkit-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Chrome10+,Safari5.1+ */
|
||||||
background: -o-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Opera11.10+ */
|
background: -o-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Opera11.10+ */
|
||||||
background: -ms-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* IE10+ */
|
background: -ms-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* IE10+ */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C6C6C6', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C6C6C6', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
||||||
background: linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* W3C */
|
background: linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* W3C */
|
||||||
/* for ie */
|
/* for ie */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
||||||
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
@ -236,19 +314,19 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', end
|
||||||
}
|
}
|
||||||
.openerp .secondary_menu h3 {
|
.openerp .secondary_menu h3 {
|
||||||
padding: 0 0 2px;
|
padding: 0 0 2px;
|
||||||
background: #949292; /* Old browsers */
|
background: #949292; /* Old browsers */
|
||||||
background: -moz-linear-gradient(top, #949292 0%, #6d6b6b 87%, #282828 99%); /* FF3.6+ */
|
background: -moz-linear-gradient(top, #949292 0%, #6d6b6b 87%, #282828 99%); /* FF3.6+ */
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#949292), color-stop(87%,#6d6b6b), color-stop(99%,#282828)); /* Chrome,Safari4+ */
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#949292), color-stop(87%,#6d6b6b), color-stop(99%,#282828)); /* Chrome,Safari4+ */
|
||||||
background: -webkit-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Chrome10+,Safari5.1+ */
|
background: -webkit-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Chrome10+,Safari5.1+ */
|
||||||
background: -o-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Opera11.10+ */
|
background: -o-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Opera11.10+ */
|
||||||
background: -ms-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* IE10+ */
|
background: -ms-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* IE10+ */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */
|
||||||
background: linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* W3C */
|
background: linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* W3C */
|
||||||
/* for ie9 */
|
/* for ie9 */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */
|
||||||
border: none;
|
border: none;
|
||||||
/* overriding jquery ui */
|
/* overriding jquery ui */
|
||||||
-moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px;
|
-moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px;
|
||||||
}
|
}
|
||||||
.openerp .secondary_menu h4 {
|
.openerp .secondary_menu h4 {
|
||||||
padding: 0 0 2px 10px;
|
padding: 0 0 2px 10px;
|
||||||
|
@ -274,17 +352,16 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', end
|
||||||
.openerp .secondary_menu h4:hover,
|
.openerp .secondary_menu h4:hover,
|
||||||
.openerp .secondary_menu h4:active,
|
.openerp .secondary_menu h4:active,
|
||||||
.openerp .secondary_menu h4.active {
|
.openerp .secondary_menu h4.active {
|
||||||
background: #ffffff; /* Old browsers */
|
background: #ffffff; /* Old browsers */
|
||||||
background: -moz-linear-gradient(top, #ffffff 0%, #d8d8d8 11%, #afafaf 86%, #333333 91%, #5a5858 96%); /* FF3.6+ */
|
background: -moz-linear-gradient(top, #ffffff 0%, #d8d8d8 11%, #afafaf 86%, #333333 91%, #5a5858 96%); /* FF3.6+ */
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(11%,#d8d8d8), color-stop(86%,#afafaf), color-stop(91%,#333333), color-stop(96%,#5a5858)); /* Chrome,Safari4+ */
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(11%,#d8d8d8), color-stop(86%,#afafaf), color-stop(91%,#333333), color-stop(96%,#5a5858)); /* Chrome,Safari4+ */
|
||||||
background: -webkit-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Chrome10+,Safari5.1+ */
|
background: -webkit-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Chrome10+,Safari5.1+ */
|
||||||
background: -o-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Opera11.10+ */
|
background: -o-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Opera11.10+ */
|
||||||
background: -ms-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* IE10+ */
|
background: -ms-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* IE10+ */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#5A5858',GradientType=0 ); /* IE6-9 */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#5A5858',GradientType=0 ); /* IE6-9 */
|
||||||
background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* W3C */
|
background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* W3C */
|
||||||
/* overriding jquery ui */
|
/* overriding jquery ui */
|
||||||
-moz-border-radius-topright: 0; -webkit-border-top-right-radius: 0; border-top-right-radius: 0;
|
-moz-border-radius-topright: 0; -webkit-border-top-right-radius: 0; border-top-right-radius: 0;
|
||||||
|
|
||||||
color: #3f3d3d;
|
color: #3f3d3d;
|
||||||
text-shadow: #fff 0 1px 0;
|
text-shadow: #fff 0 1px 0;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
|
@ -314,7 +391,6 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
||||||
float: left;
|
float: left;
|
||||||
height: 63px;
|
height: 63px;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
margin-right: 10px;
|
|
||||||
border: 1px solid white;
|
border: 1px solid white;
|
||||||
border-right-color: black;
|
border-right-color: black;
|
||||||
border-bottom-color: black;
|
border-bottom-color: black;
|
||||||
|
@ -1096,3 +1172,10 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openerp .dhx_mini_calendar {
|
||||||
|
-moz-box-shadow: none;
|
||||||
|
-khtml-box-shadow: none;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
|
@ -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: 2.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 81 B |
Binary file not shown.
After Width: | Height: | Size: 182 B |
|
@ -1,5 +1,5 @@
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
// OpenERP initialisation and black magic about the pool
|
// OpenERP Web Boostrap
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,9 +57,8 @@
|
||||||
// OpenERP base module split
|
// OpenERP base module split
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
|
|
||||||
/** @namespace */
|
|
||||||
openerp.base = function(instance) {
|
openerp.base = function(instance) {
|
||||||
openerp.base.controller(instance);
|
openerp.base.core(instance);
|
||||||
openerp.base.dates(instance);
|
openerp.base.dates(instance);
|
||||||
openerp.base.chrome(instance);
|
openerp.base.chrome(instance);
|
||||||
openerp.base.data(instance);
|
openerp.base.data(instance);
|
||||||
|
@ -87,6 +86,9 @@ openerp.base = function(instance) {
|
||||||
if (openerp.base.view_tree) {
|
if (openerp.base.view_tree) {
|
||||||
openerp.base.view_tree(instance);
|
openerp.base.view_tree(instance);
|
||||||
}
|
}
|
||||||
|
if (openerp.base.data_export) {
|
||||||
|
openerp.base.data_export(instance);
|
||||||
|
}
|
||||||
if (openerp.base.import){
|
if (openerp.base.import){
|
||||||
openerp.base.import(instance);
|
openerp.base.import(instance);
|
||||||
}
|
}
|
|
@ -4,241 +4,7 @@
|
||||||
|
|
||||||
openerp.base.chrome = function(openerp) {
|
openerp.base.chrome = function(openerp) {
|
||||||
|
|
||||||
/**
|
openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{
|
||||||
* 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 || {}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenERP session aware controller
|
|
||||||
* a controller takes an already existing dom element and manage it
|
|
||||||
*/
|
|
||||||
openerp.base.Controller = openerp.base.Controller.extend( /** @lends openerp.base.Controller# */{
|
|
||||||
init: function(parent, element_id) {
|
|
||||||
this._super(parent, element_id);
|
|
||||||
if(this.controller_parent && this.controller_parent.session) {
|
|
||||||
this.session = this.controller_parent.session;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
},
|
|
||||||
do_action: function(action, on_finished) {
|
|
||||||
return this.parent.do_action(action, on_finished);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenERP session aware widget
|
|
||||||
* A widget is a controller that doesnt take an element_id
|
|
||||||
* it render its own html render() that you should insert into the dom
|
|
||||||
* and bind it at 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) {
|
|
||||||
this._super(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;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 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 : {}));
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* "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 () {
|
|
||||||
if(this.$element != null) {
|
|
||||||
this.$element.remove();
|
|
||||||
}
|
|
||||||
this._super();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
openerp.base.Session = openerp.base.Controller.extend( /** @lends openerp.base.Session# */{
|
|
||||||
/**
|
/**
|
||||||
* @constructs
|
* @constructs
|
||||||
* @param element_id to use for exception reporting
|
* @param element_id to use for exception reporting
|
||||||
|
@ -506,7 +272,7 @@ openerp.base.Session = openerp.base.Controller.extend( /** @lends openerp.base.S
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Notification = openerp.base.Controller.extend({
|
openerp.base.Notification = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id) {
|
init: function(parent, element_id) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.$element.notify({
|
this.$element.notify({
|
||||||
|
@ -528,7 +294,7 @@ openerp.base.Notification = openerp.base.Controller.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Dialog = openerp.base.BaseWidget.extend({
|
openerp.base.Dialog = openerp.base.OldWidget.extend({
|
||||||
dialog_title: "",
|
dialog_title: "",
|
||||||
identifier_prefix: 'dialog',
|
identifier_prefix: 'dialog',
|
||||||
init: function (parent, options) {
|
init: function (parent, options) {
|
||||||
|
@ -544,8 +310,8 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({
|
||||||
max_height: '100%',
|
max_height: '100%',
|
||||||
autoOpen: false,
|
autoOpen: false,
|
||||||
buttons: {},
|
buttons: {},
|
||||||
close: function () {
|
beforeClose: function () {
|
||||||
self.stop();
|
self.on_close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (var f in this) {
|
for (var f in this) {
|
||||||
|
@ -609,7 +375,15 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({
|
||||||
this.set_options(options);
|
this.set_options(options);
|
||||||
this.$dialog.dialog(this.options).dialog('open');
|
this.$dialog.dialog(this.options).dialog('open');
|
||||||
},
|
},
|
||||||
|
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 () {
|
stop: function () {
|
||||||
|
// Destroy widget
|
||||||
|
this.close();
|
||||||
this.$dialog.dialog('destroy');
|
this.$dialog.dialog('destroy');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -643,14 +417,14 @@ openerp.base.CrashManager = openerp.base.Dialog.extend({
|
||||||
this.dialog_title = "OpenERP Error";
|
this.dialog_title = "OpenERP Error";
|
||||||
this.template = 'DialogTraceback';
|
this.template = 'DialogTraceback';
|
||||||
this.open({
|
this.open({
|
||||||
width: '80%',
|
width: 'auto',
|
||||||
height: '80%'
|
height: 'auto'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Loading = openerp.base.Controller.extend({
|
openerp.base.Loading = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id) {
|
init: function(parent, element_id) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
|
@ -669,16 +443,314 @@ openerp.base.Loading = openerp.base.Controller.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Database = openerp.base.Controller.extend({
|
openerp.base.Database = openerp.base.Widget.extend({
|
||||||
|
init: function(parent, element_id, option_id) {
|
||||||
|
this._super(parent, element_id);
|
||||||
|
this.$option_id = $('#' + option_id);
|
||||||
|
},
|
||||||
|
start: function() {
|
||||||
|
this.$element.html(QWeb.render("Database", this));
|
||||||
|
this.$element.closest(".openerp")
|
||||||
|
.removeClass("login-mode")
|
||||||
|
.addClass("database_block");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var fetch_db = this.rpc("/base/database/get_list", {}, function(result) {
|
||||||
|
self.db_list = result.db_list;
|
||||||
|
});
|
||||||
|
var fetch_langs = this.rpc("/base/session/get_lang_list", {}, function(result) {
|
||||||
|
if (result.error) {
|
||||||
|
self.display_error(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.lang_list = result.lang_list;
|
||||||
|
});
|
||||||
|
$.when(fetch_db, fetch_langs).then(function () {self.do_create();});
|
||||||
|
|
||||||
|
this.$element.find('#db-create').click(this.do_create);
|
||||||
|
this.$element.find('#db-drop').click(this.do_drop);
|
||||||
|
this.$element.find('#db-backup').click(this.do_backup);
|
||||||
|
this.$element.find('#db-restore').click(this.do_restore);
|
||||||
|
this.$element.find('#db-change-password').click(this.do_change_password);
|
||||||
|
this.$element.find('#back-to-login').click(function() {
|
||||||
|
self.stop();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
stop: function () {
|
||||||
|
this.$option_id.empty();
|
||||||
|
|
||||||
|
this.$element
|
||||||
|
.find('#db-create, #db-drop, #db-backup, #db-restore, #db-change-password, #back-to-login')
|
||||||
|
.unbind('click')
|
||||||
|
.end()
|
||||||
|
.closest(".openerp")
|
||||||
|
.addClass("login-mode")
|
||||||
|
.removeClass("database_block")
|
||||||
|
.end()
|
||||||
|
.empty();
|
||||||
|
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Converts a .serializeArray() result into a dict. Does not bother folding
|
||||||
|
* multiple identical keys into an array, last key wins.
|
||||||
|
*
|
||||||
|
* @param {Array} array
|
||||||
|
*/
|
||||||
|
to_object: function (array) {
|
||||||
|
var result = {};
|
||||||
|
_(array).each(function (record) {
|
||||||
|
result[record.name] = record.value;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Waits until the new database is done creating, then unblocks the UI and
|
||||||
|
* logs the user in as admin
|
||||||
|
*
|
||||||
|
* @param {Number} db_creation_id identifier for the db-creation operation, used to fetch the current installation progress
|
||||||
|
* @param {Object} info info fields for this database creation
|
||||||
|
* @param {String} info.db name of the database being created
|
||||||
|
* @param {String} info.password super-admin password for the database
|
||||||
|
*/
|
||||||
|
wait_for_newdb: function (db_creation_id, info) {
|
||||||
|
var self = this;
|
||||||
|
self.rpc('/base/database/progress', {
|
||||||
|
id: db_creation_id,
|
||||||
|
password: info.password
|
||||||
|
}, function (result) {
|
||||||
|
var progress = result[0];
|
||||||
|
// I'd display a progress bar, but turns out the progress status
|
||||||
|
// the server report kind-of blows goats: it's at 0 for ~75% of
|
||||||
|
// the installation, then jumps to 75%, then jumps down to either
|
||||||
|
// 0 or ~40%, then back up to 75%, then terminates. Let's keep that
|
||||||
|
// mess hidden behind a not-very-useful but not overly weird
|
||||||
|
// message instead.
|
||||||
|
if (progress < 1) {
|
||||||
|
setTimeout(function () {
|
||||||
|
self.wait_for_newdb(db_creation_id, info);
|
||||||
|
}, 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var admin = result[1][0];
|
||||||
|
setTimeout(function () {
|
||||||
|
self.stop();
|
||||||
|
self.widget_parent.do_login(
|
||||||
|
info.db, admin.login, admin.password);
|
||||||
|
$.unblockUI();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Displays an error dialog resulting from the various RPC communications
|
||||||
|
* failing over themselves
|
||||||
|
*
|
||||||
|
* @param {Object} error error description
|
||||||
|
* @param {String} error.title title of the error dialog
|
||||||
|
* @param {String} error.error message of the error dialog
|
||||||
|
*/
|
||||||
|
display_error: function (error) {
|
||||||
|
return $('<div>').dialog({
|
||||||
|
modal: true,
|
||||||
|
title: error.title,
|
||||||
|
buttons: {
|
||||||
|
Ok: function() {
|
||||||
|
$(this).dialog("close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).html(error.error);
|
||||||
|
},
|
||||||
|
do_create: function() {
|
||||||
|
var self = this;
|
||||||
|
self.$option_id.html(QWeb.render("CreateDB", self));
|
||||||
|
|
||||||
|
self.$option_id.find("form[name=create_db_form]").validate({
|
||||||
|
submitHandler: function (form) {
|
||||||
|
var fields = $(form).serializeArray();
|
||||||
|
$.blockUI();
|
||||||
|
self.rpc("/base/database/create", {'fields': fields}, function(result) {
|
||||||
|
if (result.error) {
|
||||||
|
$.unblockUI();
|
||||||
|
self.display_error(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.db_list.push(self.to_object(fields)['db_name']);
|
||||||
|
self.db_list.sort();
|
||||||
|
var form_obj = self.to_object(fields);
|
||||||
|
self.wait_for_newdb(result, {
|
||||||
|
password: form_obj['super_admin_pwd'],
|
||||||
|
db: form_obj['db_name']
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
do_drop: function() {
|
||||||
|
var self = this;
|
||||||
|
self.$option_id.html(QWeb.render("DropDB", self));
|
||||||
|
|
||||||
|
self.$option_id.find("form[name=drop_db_form]").validate({
|
||||||
|
submitHandler: function (form) {
|
||||||
|
var $form = $(form),
|
||||||
|
fields = $form.serializeArray(),
|
||||||
|
$db_list = $form.find('select[name=drop_db]'),
|
||||||
|
db = $db_list.val();
|
||||||
|
|
||||||
|
if (!confirm("Do you really want to delete the database: " + db + " ?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.rpc("/base/database/drop", {'fields': fields}, function(result) {
|
||||||
|
if (result.error) {
|
||||||
|
self.display_error(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$db_list.find(':selected').remove();
|
||||||
|
self.db_list.splice(_.indexOf(self.db_list, db, true), 1);
|
||||||
|
self.notification.notify("Dropping database", "The database '" + db + "' has been dropped");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
wait_for_file: function (token, cleanup) {
|
||||||
|
var self = this,
|
||||||
|
cookie_name = 'fileToken',
|
||||||
|
cookie_length = cookie_name.length;
|
||||||
|
this.backup_timer = setInterval(function () {
|
||||||
|
var cookies = document.cookie.split(';');
|
||||||
|
for(var i=0; i<cookies.length; ++i) {
|
||||||
|
var cookie = cookies[i].replace(/^\s*/, '');
|
||||||
|
if(!cookie.indexOf(cookie_name) === 0) { continue; }
|
||||||
|
var cookie_val = cookie.substring(cookie_length + 1);
|
||||||
|
if(parseInt(cookie_val, 10) !== token) { continue; }
|
||||||
|
|
||||||
|
// clear waiter
|
||||||
|
clearInterval(self.backup_timer);
|
||||||
|
// clear cookie
|
||||||
|
document.cookie = _.sprintf("%s=;expires=%s;path=/",
|
||||||
|
cookie_name, new Date().toGMTString());
|
||||||
|
|
||||||
|
if (cleanup) { cleanup(); }
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
},
|
||||||
|
do_backup: function() {
|
||||||
|
var self = this;
|
||||||
|
self.$option_id.html(QWeb.render("BackupDB", self));
|
||||||
|
|
||||||
|
self.$option_id.find("form[name=backup_db_form]").validate({
|
||||||
|
submitHandler: function (form) {
|
||||||
|
$.blockUI();
|
||||||
|
// need to detect when the file is done downloading (not used
|
||||||
|
// yet, but we'll need it to fix the UI e.g. with a throbber
|
||||||
|
// while dump is being generated), iframe load event only fires
|
||||||
|
// when the iframe content loads, so we need to go smarter:
|
||||||
|
// http://geekswithblogs.net/GruffCode/archive/2010/10/28/detecting-the-file-download-dialog-in-the-browser.aspx
|
||||||
|
var $target = $('#backup-target'),
|
||||||
|
token = new Date().getTime();
|
||||||
|
if (!$target.length) {
|
||||||
|
$target = $('<iframe id="backup-target" style="display: none;">')
|
||||||
|
.appendTo(document.body)
|
||||||
|
.load(function () {
|
||||||
|
$.unblockUI();
|
||||||
|
clearInterval(self.backup_timer);
|
||||||
|
var error = this.contentDocument.body
|
||||||
|
.firstChild.data
|
||||||
|
.split('|');
|
||||||
|
self.display_error({
|
||||||
|
title: error[0],
|
||||||
|
error: error[1]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$(form).find('input[name=token]').val(token);
|
||||||
|
form.submit();
|
||||||
|
|
||||||
|
self.wait_for_file(token, function () {
|
||||||
|
$.unblockUI();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
do_restore: function() {
|
||||||
|
var self = this;
|
||||||
|
self.$option_id.html(QWeb.render("RestoreDB", self));
|
||||||
|
|
||||||
|
self.$option_id.find("form[name=restore_db_form]").validate({
|
||||||
|
submitHandler: function (form) {
|
||||||
|
$.blockUI();
|
||||||
|
$(form).ajaxSubmit({
|
||||||
|
url: '/base/database/restore',
|
||||||
|
type: 'POST',
|
||||||
|
resetForm: true,
|
||||||
|
success: function (body) {
|
||||||
|
// TODO: ui manipulations
|
||||||
|
// note: response objects don't work, but we have the
|
||||||
|
// HTTP body of the response~~
|
||||||
|
|
||||||
|
// If empty body, everything went fine
|
||||||
|
if (!body) { return; }
|
||||||
|
|
||||||
|
if (body.indexOf('403 Forbidden') !== -1) {
|
||||||
|
self.display_error({
|
||||||
|
title: 'Access Denied',
|
||||||
|
error: 'Incorrect super-administrator password'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.display_error({
|
||||||
|
title: 'Restore Database',
|
||||||
|
error: 'Could not restore the database'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
$.unblockUI();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
do_change_password: function() {
|
||||||
|
var self = this;
|
||||||
|
self.$option_id.html(QWeb.render("Change_DB_Pwd", self));
|
||||||
|
|
||||||
|
self.$option_id.find("form[name=change_pwd_form]").validate({
|
||||||
|
messages: {
|
||||||
|
old_pwd: "Please enter your previous password",
|
||||||
|
new_pwd: "Please enter your new password",
|
||||||
|
confirm_pwd: {
|
||||||
|
required: "Please confirm your new password",
|
||||||
|
equalTo: "The confirmation does not match the password"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submitHandler: function (form) {
|
||||||
|
self.rpc("/base/database/change_password", {
|
||||||
|
'fields': $(form).serializeArray()
|
||||||
|
}, function(result) {
|
||||||
|
if (result.error) {
|
||||||
|
self.display_error(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.notification.notify("Changed Password", "Password has been changed successfully");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Login = openerp.base.Controller.extend({
|
openerp.base.Login = openerp.base.Widget.extend({
|
||||||
remember_creditentials: true,
|
remember_creditentials: true,
|
||||||
|
|
||||||
init: function(parent, element_id) {
|
init: function(parent, element_id) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.has_local_storage = typeof(localStorage) != 'undefined';
|
this.has_local_storage = typeof(localStorage) != 'undefined';
|
||||||
this.selected_db = null;
|
this.selected_db = null;
|
||||||
this.selected_login = null;
|
this.selected_login = null;
|
||||||
|
|
||||||
if (this.has_local_storage && this.remember_creditentials) {
|
if (this.has_local_storage && this.remember_creditentials) {
|
||||||
this.selected_db = localStorage.getItem('last_db_login_success');
|
this.selected_db = localStorage.getItem('last_db_login_success');
|
||||||
this.selected_login = localStorage.getItem('last_login_login_success');
|
this.selected_login = localStorage.getItem('last_login_login_success');
|
||||||
|
@ -691,7 +763,7 @@ openerp.base.Login = openerp.base.Controller.extend({
|
||||||
},
|
},
|
||||||
start: function() {
|
start: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.rpc("/base/database/get_databases_list", {}, function(result) {
|
this.rpc("/base/database/get_list", {}, function(result) {
|
||||||
self.db_list = result.db_list;
|
self.db_list = result.db_list;
|
||||||
self.display();
|
self.display();
|
||||||
}, function() {
|
}, function() {
|
||||||
|
@ -699,7 +771,16 @@ openerp.base.Login = openerp.base.Controller.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
display: function() {
|
display: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
this.$element.html(QWeb.render("Login", this));
|
this.$element.html(QWeb.render("Login", this));
|
||||||
|
this.database = new openerp.base.Database(
|
||||||
|
this, "oe_database", "oe_db_options");
|
||||||
|
|
||||||
|
this.$element.find('#oe-db-config').click(function() {
|
||||||
|
self.database.start();
|
||||||
|
});
|
||||||
|
|
||||||
this.$element.find("form").submit(this.on_submit);
|
this.$element.find("form").submit(this.on_submit);
|
||||||
},
|
},
|
||||||
on_login_invalid: function() {
|
on_login_invalid: function() {
|
||||||
|
@ -710,13 +791,22 @@ openerp.base.Login = openerp.base.Controller.extend({
|
||||||
},
|
},
|
||||||
on_submit: function(ev) {
|
on_submit: function(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
var self = this;
|
|
||||||
var $e = this.$element;
|
var $e = this.$element;
|
||||||
var db = $e.find("form [name=db]").val();
|
var db = $e.find("form [name=db]").val();
|
||||||
var login = $e.find("form input[name=login]").val();
|
var login = $e.find("form input[name=login]").val();
|
||||||
var password = $e.find("form input[name=password]").val();
|
var password = $e.find("form input[name=password]").val();
|
||||||
//$e.hide();
|
|
||||||
// Should hide then call callback
|
this.do_login(db, login, password);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Performs actual login operation, and UI-related stuff
|
||||||
|
*
|
||||||
|
* @param {String} db database to log in
|
||||||
|
* @param {String} login user login
|
||||||
|
* @param {String} password user password
|
||||||
|
*/
|
||||||
|
do_login: function (db, login, password) {
|
||||||
|
var self = this;
|
||||||
this.session.session_login(db, login, password, function() {
|
this.session.session_login(db, login, password, function() {
|
||||||
if(self.session.session_is_valid()) {
|
if(self.session.session_is_valid()) {
|
||||||
if (self.has_local_storage) {
|
if (self.has_local_storage) {
|
||||||
|
@ -750,7 +840,7 @@ openerp.base.Login = openerp.base.Controller.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Header = openerp.base.Controller.extend({
|
openerp.base.Header = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id) {
|
init: function(parent, element_id) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
},
|
},
|
||||||
|
@ -764,7 +854,7 @@ openerp.base.Header = openerp.base.Controller.extend({
|
||||||
on_logout: function() {}
|
on_logout: function() {}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Menu = openerp.base.Controller.extend({
|
openerp.base.Menu = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id, secondary_menu_id) {
|
init: function(parent, element_id, secondary_menu_id) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.secondary_menu_id = secondary_menu_id;
|
this.secondary_menu_id = secondary_menu_id;
|
||||||
|
@ -845,16 +935,16 @@ 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) {
|
init: function(element_id) {
|
||||||
this._super(null, element_id);
|
this._super(null, element_id);
|
||||||
|
|
||||||
|
@ -871,7 +961,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
|
||||||
this.crashmanager.start(false);
|
this.crashmanager.start(false);
|
||||||
|
|
||||||
// Do you autorize this ? will be replaced by notify() in controller
|
// Do you autorize this ? will be replaced by notify() in controller
|
||||||
openerp.base.Controller.prototype.notification = new openerp.base.Notification(this, "oe_notification");
|
openerp.base.Widget.prototype.notification = new openerp.base.Notification(this, "oe_notification");
|
||||||
|
|
||||||
this.header = new openerp.base.Header(this, "oe_header");
|
this.header = new openerp.base.Header(this, "oe_header");
|
||||||
this.login = new openerp.base.Login(this, "oe_login");
|
this.login = new openerp.base.Login(this, "oe_login");
|
||||||
|
@ -883,6 +973,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
|
||||||
|
|
||||||
this.menu = new openerp.base.Menu(this, "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);
|
this.menu.on_action.add(this.on_menu_action);
|
||||||
|
|
||||||
},
|
},
|
||||||
start: function() {
|
start: function() {
|
||||||
this.session.start();
|
this.session.start();
|
||||||
|
|
|
@ -1,248 +0,0 @@
|
||||||
/*---------------------------------------------------------
|
|
||||||
* OpenERP controller framework
|
|
||||||
*--------------------------------------------------------*/
|
|
||||||
|
|
||||||
openerp.base.controller = function(instance) {
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
instance.base.Class = window.Class
|
|
||||||
|
|
||||||
instance.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}
|
|
||||||
*/
|
|
||||||
instance.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 = instance.base.Controller.prototype.init;
|
|
||||||
var tmpclass = claz.extend(newer);
|
|
||||||
return tmpclass.extend(add || {});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenERP Controller
|
|
||||||
* TODO merge BaseWidget with Controller
|
|
||||||
*/
|
|
||||||
instance.base.Controller = instance.base.Class.extend( /** @lends instance.base.Controller# */{
|
|
||||||
/**
|
|
||||||
* @constructs
|
|
||||||
* rpc operations, event binding and callback calling should be done in
|
|
||||||
* start() instead of init so that events can be hooked in between.
|
|
||||||
*/
|
|
||||||
init: function(parent, element_id) {
|
|
||||||
this.element_id = element_id;
|
|
||||||
this.$element = $('#' + element_id);
|
|
||||||
if (element_id) {
|
|
||||||
instance.screen[element_id] = this;
|
|
||||||
}
|
|
||||||
// save the parent children relationship
|
|
||||||
this.controller_parent = parent;
|
|
||||||
this.controller_children = [];
|
|
||||||
if(parent && parent.controller_children) {
|
|
||||||
parent.controller_children.push(this);
|
|
||||||
}
|
|
||||||
// backward compatibility
|
|
||||||
this.parent = this.controller_parent;
|
|
||||||
this.children = this.controller_children;
|
|
||||||
|
|
||||||
// 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] = instance.base.callback(this, this[name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Event binding, rpc and callback calling required to initialize the
|
|
||||||
* object should 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() {
|
|
||||||
if (this.parent && this.parent.children) {
|
|
||||||
this.parent.children = _.without(this.parent.children, this);
|
|
||||||
this.parent.controller_children = this.parent.children;
|
|
||||||
}
|
|
||||||
this.parent = null;
|
|
||||||
this.controller_parent = null;
|
|
||||||
},
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
|
|
@ -0,0 +1,572 @@
|
||||||
|
/*---------------------------------------------------------
|
||||||
|
* 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)
|
||||||
|
openerp.base.Class = function(){};
|
||||||
|
|
||||||
|
// Create a new Class that inherits from this class
|
||||||
|
openerp.base.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.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 the Widget 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, it is 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() {
|
||||||
|
* this._super();
|
||||||
|
* // stuff you want to make after the rendering, `this.$element` holds a correct 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-',
|
||||||
|
/**
|
||||||
|
* Construct the widget and set its parent if a parent is given.
|
||||||
|
*
|
||||||
|
* @constructs
|
||||||
|
* @param {openerp.base.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:
|
|
@ -18,7 +18,7 @@ openerp.base.serialize_sort = function (criterion) {
|
||||||
}).join(', ');
|
}).join(', ');
|
||||||
};
|
};
|
||||||
|
|
||||||
openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.base.DataGroup# */{
|
openerp.base.DataGroup = openerp.base.Widget.extend( /** @lends openerp.base.DataGroup# */{
|
||||||
/**
|
/**
|
||||||
* Management interface between views and grouped collections of OpenERP
|
* Management interface between views and grouped collections of OpenERP
|
||||||
* records.
|
* records.
|
||||||
|
@ -30,7 +30,7 @@ openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.bas
|
||||||
* content of the current grouping level.
|
* content of the current grouping level.
|
||||||
*
|
*
|
||||||
* @constructs
|
* @constructs
|
||||||
* @extends openerp.base.Controller
|
* @extends openerp.base.Widget
|
||||||
*
|
*
|
||||||
* @param {openerp.base.Session} session Current OpenERP session
|
* @param {openerp.base.Session} session Current OpenERP session
|
||||||
* @param {String} model name of the model managed by this DataGroup
|
* @param {String} model name of the model managed by this DataGroup
|
||||||
|
@ -232,13 +232,13 @@ openerp.base.StaticDataGroup = openerp.base.GrouplessDataGroup.extend( /** @lend
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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
|
* DateaManagement interface between views and the collection of selected
|
||||||
* OpenERP records (represents the view's state?)
|
* OpenERP records (represents the view's state?)
|
||||||
*
|
*
|
||||||
* @constructs
|
* @constructs
|
||||||
* @extends openerp.base.Controller
|
* @extends openerp.base.Widget
|
||||||
*
|
*
|
||||||
* @param {String} model the OpenERP model this dataset will manage
|
* @param {String} model the OpenERP model this dataset will manage
|
||||||
*/
|
*/
|
||||||
|
@ -291,14 +291,18 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||||
* Read the indexed record.
|
* Read the indexed record.
|
||||||
*/
|
*/
|
||||||
read_index: function (fields, callback) {
|
read_index: function (fields, callback) {
|
||||||
|
var def = $.Deferred().then(callback);
|
||||||
if (_.isEmpty(this.ids)) {
|
if (_.isEmpty(this.ids)) {
|
||||||
return $.Deferred().reject().promise();
|
def.reject();
|
||||||
} else {
|
} else {
|
||||||
fields = fields || false;
|
fields = fields || false;
|
||||||
return this.read_ids([this.ids[this.index]], fields, function(records) {
|
return this.read_ids([this.ids[this.index]], fields).then(function(records) {
|
||||||
callback(records[0]);
|
def.resolve(records[0]);
|
||||||
|
}, function() {
|
||||||
|
def.reject.apply(def, arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return def.promise();
|
||||||
},
|
},
|
||||||
default_get: function(fields, callback) {
|
default_get: function(fields, callback) {
|
||||||
return this.rpc('/base/dataset/default_get', {
|
return this.rpc('/base/dataset/default_get', {
|
||||||
|
@ -492,24 +496,33 @@ openerp.base.BufferedDataSet = openerp.base.DataSetStatic.extend({
|
||||||
this.to_create.push(cached);
|
this.to_create.push(cached);
|
||||||
this.cache.push(cached);
|
this.cache.push(cached);
|
||||||
var to_return = $.Deferred().then(callback);
|
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();
|
return to_return.promise();
|
||||||
},
|
},
|
||||||
write: function (id, data, callback) {
|
write: function (id, data, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var record = _.detect(this.to_create, function(x) {return x.id === id;});
|
var record = _.detect(this.to_create, function(x) {return x.id === id;});
|
||||||
record = record || _.detect(this.to_write, function(x) {return x.id === id;});
|
record = record || _.detect(this.to_write, function(x) {return x.id === id;});
|
||||||
|
var dirty = false;
|
||||||
if (record) {
|
if (record) {
|
||||||
|
for (k in data) {
|
||||||
|
if (record.values[k] === undefined || record.values[k] !== data[k]) {
|
||||||
|
dirty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
$.extend(record.values, data);
|
$.extend(record.values, data);
|
||||||
} else {
|
} else {
|
||||||
|
dirty = true;
|
||||||
record = {id: id, values: data};
|
record = {id: id, values: data};
|
||||||
self.to_write.push(record);
|
self.to_write.push(record);
|
||||||
}
|
}
|
||||||
var cached = _.detect(this.cache, function(x) {return x.id === id;});
|
var cached = _.detect(this.cache, function(x) {return x.id === id;});
|
||||||
$.extend(cached.values, record.values);
|
$.extend(cached.values, record.values);
|
||||||
|
if (dirty)
|
||||||
this.on_change();
|
this.on_change();
|
||||||
var to_return = $.Deferred().then(callback);
|
var to_return = $.Deferred().then(callback);
|
||||||
setTimeout(function () {to_return.resolve({result: true});}, 0);
|
to_return.resolve({result: true});
|
||||||
return to_return.promise();
|
return to_return.promise();
|
||||||
},
|
},
|
||||||
unlink: function(ids, callback, error_callback) {
|
unlink: function(ids, callback, error_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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
|
@ -20,7 +20,6 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
init: function(parent, element_id, dataset, view_id, options) {
|
init: function(parent, element_id, dataset, view_id, options) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.set_default_options();
|
this.set_default_options();
|
||||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
|
||||||
this.dataset = dataset;
|
this.dataset = dataset;
|
||||||
this.model = dataset.model;
|
this.model = dataset.model;
|
||||||
this.view_id = view_id;
|
this.view_id = view_id;
|
||||||
|
@ -31,8 +30,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
this.datarecord = {};
|
this.datarecord = {};
|
||||||
this.ready = false;
|
this.ready = false;
|
||||||
this.show_invalid = true;
|
this.show_invalid = true;
|
||||||
this.touched = false;
|
this.dirty = false;
|
||||||
this.flags = this.view_manager.flags || {};
|
|
||||||
this.default_focus_field = null;
|
this.default_focus_field = null;
|
||||||
this.default_focus_button = null;
|
this.default_focus_button = null;
|
||||||
this.registry = openerp.base.form.widgets;
|
this.registry = openerp.base.form.widgets;
|
||||||
|
@ -50,9 +48,6 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
return def.promise();
|
return def.promise();
|
||||||
} else {
|
} else {
|
||||||
var context = new openerp.base.CompoundContext(this.dataset.get_context());
|
var context = new openerp.base.CompoundContext(this.dataset.get_context());
|
||||||
if (this.view_manager.action && this.view_manager.action.context) {
|
|
||||||
context.add(this.view_manager.action.context);
|
|
||||||
}
|
|
||||||
return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id,
|
return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id,
|
||||||
toolbar: this.options.sidebar, context: context}, this.on_loaded);
|
toolbar: this.options.sidebar, context: context}, this.on_loaded);
|
||||||
}
|
}
|
||||||
|
@ -93,9 +88,10 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
if (this.options.sidebar && this.options.sidebar_id) {
|
if (this.options.sidebar && this.options.sidebar_id) {
|
||||||
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
||||||
this.sidebar.start();
|
this.sidebar.start();
|
||||||
this.sidebar.attachments = new openerp.base.form.SidebarAttachments(this.sidebar, this.sidebar.add_section("Attachments"), this);
|
|
||||||
this.sidebar.add_toolbar(data.fields_view.toolbar);
|
|
||||||
this.sidebar.do_unfold();
|
this.sidebar.do_unfold();
|
||||||
|
this.sidebar.attachments = new openerp.base.form.SidebarAttachments(this.sidebar, this.sidebar.add_section('attachments', "Attachments"), this);
|
||||||
|
this.sidebar.add_toolbar(data.fields_view.toolbar);
|
||||||
|
this.set_common_sidebar_sections(this.sidebar);
|
||||||
}
|
}
|
||||||
this.has_been_loaded.resolve();
|
this.has_been_loaded.resolve();
|
||||||
},
|
},
|
||||||
|
@ -134,22 +130,22 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
this.$form_header.find('.oe_form_on_update').show();
|
this.$form_header.find('.oe_form_on_update').show();
|
||||||
this.$form_header.find('button.oe_form_button_new').show();
|
this.$form_header.find('button.oe_form_button_new').show();
|
||||||
}
|
}
|
||||||
this.touched = false;
|
this.dirty = false;
|
||||||
this.datarecord = record;
|
this.datarecord = record;
|
||||||
for (var f in this.fields) {
|
for (var f in this.fields) {
|
||||||
var field = this.fields[f];
|
var field = this.fields[f];
|
||||||
field.touched = false;
|
field.dirty = false;
|
||||||
field.set_value(this.datarecord[f] || false);
|
field.set_value(this.datarecord[f] || false);
|
||||||
field.validate();
|
field.validate();
|
||||||
}
|
}
|
||||||
if (!record.id) {
|
if (!record.id) {
|
||||||
// New record: Second pass in order to trigger the onchanges
|
// New record: Second pass in order to trigger the onchanges
|
||||||
this.touched = true;
|
this.dirty = true;
|
||||||
this.show_invalid = false;
|
this.show_invalid = false;
|
||||||
for (var f in record) {
|
for (var f in record) {
|
||||||
var field = this.fields[f];
|
var field = this.fields[f];
|
||||||
if (field) {
|
if (field) {
|
||||||
field.touched = true;
|
field.dirty = true;
|
||||||
this.do_onchange(field);
|
this.do_onchange(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +264,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
processed.push(field.name);
|
processed.push(field.name);
|
||||||
if (field.get_value() != value) {
|
if (field.get_value() != value) {
|
||||||
field.set_value(value);
|
field.set_value(value);
|
||||||
field.touched = true;
|
field.dirty = true;
|
||||||
if (_.indexOf(processed, field.name) < 0) {
|
if (_.indexOf(processed, field.name) < 0) {
|
||||||
this.do_onchange(field, processed);
|
this.do_onchange(field, processed);
|
||||||
}
|
}
|
||||||
|
@ -316,37 +312,40 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
if (!this.ready) {
|
if (!this.ready) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var invalid = false,
|
var form_dirty = false,
|
||||||
|
form_invalid = false,
|
||||||
values = {},
|
values = {},
|
||||||
first_invalid_field = null;
|
first_invalid_field = null;
|
||||||
for (var f in this.fields) {
|
for (var f in this.fields) {
|
||||||
f = this.fields[f];
|
f = this.fields[f];
|
||||||
if (f.invalid) {
|
if (!f.is_valid()) {
|
||||||
invalid = true;
|
form_invalid = true;
|
||||||
f.update_dom();
|
f.update_dom();
|
||||||
if (!first_invalid_field) {
|
if (!first_invalid_field) {
|
||||||
first_invalid_field = f;
|
first_invalid_field = f;
|
||||||
}
|
}
|
||||||
} else if (f.touched) {
|
} else if (f.is_dirty()) {
|
||||||
|
form_dirty = true;
|
||||||
values[f.name] = f.get_value();
|
values[f.name] = f.get_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (invalid) {
|
if (form_invalid) {
|
||||||
first_invalid_field.focus();
|
first_invalid_field.focus();
|
||||||
this.on_invalid();
|
this.on_invalid();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else if (form_dirty) {
|
||||||
this.log("About to save", values);
|
this.log("About to save", values);
|
||||||
if (!this.datarecord.id) {
|
if (!this.datarecord.id) {
|
||||||
this.dataset.create(values, function(r) {
|
return this.dataset.create(values, function(r) {
|
||||||
self.on_created(r, success, prepend_on_create);
|
self.on_created(r, success, prepend_on_create);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.dataset.write(this.datarecord.id, values, function(r) {
|
return this.dataset.write(this.datarecord.id, values, function(r) {
|
||||||
self.on_saved(r, success);
|
self.on_saved(r, success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return true;
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
do_save_edit: function() {
|
do_save_edit: function() {
|
||||||
|
@ -360,7 +359,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
on_invalid: function() {
|
on_invalid: function() {
|
||||||
var msg = "<ul>";
|
var msg = "<ul>";
|
||||||
_.each(this.fields, function(f) {
|
_.each(this.fields, function(f) {
|
||||||
if (f.invalid) {
|
if (!f.is_valid()) {
|
||||||
msg += "<li>" + f.string + "</li>";
|
msg += "<li>" + f.string + "</li>";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -443,7 +442,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||||
/** @namespace */
|
/** @namespace */
|
||||||
openerp.base.form = {};
|
openerp.base.form = {};
|
||||||
|
|
||||||
openerp.base.form.SidebarAttachments = openerp.base.Controller.extend({
|
openerp.base.form.SidebarAttachments = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id, form_view) {
|
init: function(parent, element_id, form_view) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.view = form_view;
|
this.view = form_view;
|
||||||
|
@ -550,7 +549,7 @@ openerp.base.form.compute_domain = function(expr, fields) {
|
||||||
return _.all(stack);
|
return _.all(stack);
|
||||||
};
|
};
|
||||||
|
|
||||||
openerp.base.form.Widget = openerp.base.Controller.extend({
|
openerp.base.form.Widget = openerp.base.Widget.extend({
|
||||||
template: 'Widget',
|
template: 'Widget',
|
||||||
init: function(view, node) {
|
init: function(view, node) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
|
@ -716,6 +715,10 @@ openerp.base.form.WidgetButton = openerp.base.form.Widget.extend({
|
||||||
init: function(view, node) {
|
init: function(view, node) {
|
||||||
this._super(view, node);
|
this._super(view, node);
|
||||||
this.template = "WidgetButton";
|
this.template = "WidgetButton";
|
||||||
|
if (this.string) {
|
||||||
|
// We don't have button key bindings in the webclient
|
||||||
|
this.string = this.string.replace(/_/g, '');
|
||||||
|
}
|
||||||
if (node.attrs.default_focus == '1') {
|
if (node.attrs.default_focus == '1') {
|
||||||
// TODO fme: provide enter key binding to widgets
|
// TODO fme: provide enter key binding to widgets
|
||||||
this.view.default_focus_button = this;
|
this.view.default_focus_button = this;
|
||||||
|
@ -727,7 +730,7 @@ openerp.base.form.WidgetButton = openerp.base.form.Widget.extend({
|
||||||
},
|
},
|
||||||
on_click: function(saved) {
|
on_click: function(saved) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (!this.node.attrs.special && this.view.touched && saved !== true) {
|
if (!this.node.attrs.special && this.view.dirty && saved !== true) {
|
||||||
this.view.do_save(function() {
|
this.view.do_save(function() {
|
||||||
self.on_click(true);
|
self.on_click(true);
|
||||||
});
|
});
|
||||||
|
@ -772,11 +775,12 @@ openerp.base.form.WidgetLabel = openerp.base.form.Widget.extend({
|
||||||
if (this.node.tag == 'label' && this.node.attrs.colspan) {
|
if (this.node.tag == 'label' && this.node.attrs.colspan) {
|
||||||
this.is_field_label = false;
|
this.is_field_label = false;
|
||||||
this.template = "WidgetParagraph";
|
this.template = "WidgetParagraph";
|
||||||
|
this.colspan = this.node.attrs.colspan;
|
||||||
} else {
|
} else {
|
||||||
this.is_field_label = true;
|
this.is_field_label = true;
|
||||||
this.template = "WidgetLabel";
|
this.template = "WidgetLabel";
|
||||||
}
|
|
||||||
this.colspan = 1;
|
this.colspan = 1;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
if (this['for'] && this.type !== 'label') {
|
if (this['for'] && this.type !== 'label') {
|
||||||
|
@ -807,7 +811,7 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
||||||
this.readonly = this.modifiers['readonly'] === true;
|
this.readonly = this.modifiers['readonly'] === true;
|
||||||
this.required = this.modifiers['required'] === true;
|
this.required = this.modifiers['required'] === true;
|
||||||
this.invalid = false;
|
this.invalid = false;
|
||||||
this.touched = false;
|
this.dirty = false;
|
||||||
},
|
},
|
||||||
set_value: function(value) {
|
set_value: function(value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -820,21 +824,29 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
||||||
get_value: function() {
|
get_value: function() {
|
||||||
return this.value;
|
return this.value;
|
||||||
},
|
},
|
||||||
|
is_valid: function() {
|
||||||
|
return !this.invalid;
|
||||||
|
},
|
||||||
|
is_dirty: function() {
|
||||||
|
return this.dirty;
|
||||||
|
},
|
||||||
get_on_change_value: function() {
|
get_on_change_value: function() {
|
||||||
return this.get_value();
|
return this.get_value();
|
||||||
},
|
},
|
||||||
update_dom: function() {
|
update_dom: function() {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
|
if (!this.disable_utility_classes) {
|
||||||
this.$element.toggleClass('disabled', this.readonly);
|
this.$element.toggleClass('disabled', this.readonly);
|
||||||
this.$element.toggleClass('required', this.required);
|
this.$element.toggleClass('required', this.required);
|
||||||
if (this.view.show_invalid) {
|
if (this.view.show_invalid) {
|
||||||
this.$element.toggleClass('invalid', this.invalid);
|
this.$element.toggleClass('invalid', !this.is_valid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_ui_change: function() {
|
on_ui_change: function() {
|
||||||
this.touched = this.view.touched = true;
|
this.dirty = this.view.dirty = true;
|
||||||
this.validate();
|
this.validate();
|
||||||
if (!this.invalid) {
|
if (this.is_valid()) {
|
||||||
this.set_value_from_ui();
|
this.set_value_from_ui();
|
||||||
this.view.do_onchange(this);
|
this.view.do_onchange(this);
|
||||||
this.view.on_form_changed();
|
this.view.on_form_changed();
|
||||||
|
@ -932,7 +944,7 @@ openerp.base.form.FieldEmail = openerp.base.form.FieldChar.extend({
|
||||||
this.$element.find('button').click(this.on_button_clicked);
|
this.$element.find('button').click(this.on_button_clicked);
|
||||||
},
|
},
|
||||||
on_button_clicked: function() {
|
on_button_clicked: function() {
|
||||||
if (!this.value || this.invalid) {
|
if (!this.value || !this.is_valid()) {
|
||||||
this.notification.warn("E-mail error", "Can't send email to invalid e-mail address");
|
this.notification.warn("E-mail error", "Can't send email to invalid e-mail address");
|
||||||
} else {
|
} else {
|
||||||
location.href = 'mailto:' + this.value;
|
location.href = 'mailto:' + this.value;
|
||||||
|
@ -973,7 +985,7 @@ openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({
|
||||||
if (value === false || value === undefined) {
|
if (value === false || value === undefined) {
|
||||||
// As in GTK client, floats default to 0
|
// As in GTK client, floats default to 0
|
||||||
value = 0;
|
value = 0;
|
||||||
this.touched = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
var show_value = value.toFixed(2);
|
var show_value = value.toFixed(2);
|
||||||
this.$element.find('input').val(show_value);
|
this.$element.find('input').val(show_value);
|
||||||
|
@ -993,7 +1005,7 @@ openerp.base.form.FieldInteger = openerp.base.form.FieldFloat.extend({
|
||||||
if (value === false || value === undefined) {
|
if (value === false || value === undefined) {
|
||||||
// TODO fme: check if GTK client default integers to 0 (like it does with floats)
|
// TODO fme: check if GTK client default integers to 0 (like it does with floats)
|
||||||
value = 0;
|
value = 0;
|
||||||
this.touched = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
var show_value = parseInt(value, 10);
|
var show_value = parseInt(value, 10);
|
||||||
this.$element.find('input').val(show_value);
|
this.$element.find('input').val(show_value);
|
||||||
|
@ -1080,7 +1092,7 @@ openerp.base.form.FieldFloatTime = openerp.base.form.FieldChar.extend({
|
||||||
if (value === false || value === undefined) {
|
if (value === false || value === undefined) {
|
||||||
// As in GTK client, floats default to 0
|
// As in GTK client, floats default to 0
|
||||||
value = 0;
|
value = 0;
|
||||||
this.touched = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
var show_value = _.sprintf("%02d:%02d", Math.floor(value), Math.round((value % 1) * 60));
|
var show_value = _.sprintf("%02d:%02d", Math.floor(value), Math.round((value % 1) * 60));
|
||||||
this.$element.find('input').val(show_value);
|
this.$element.find('input').val(show_value);
|
||||||
|
@ -1287,7 +1299,6 @@ openerp.base.form.dialog = function(content, options) {
|
||||||
options.autoOpen = true;
|
options.autoOpen = true;
|
||||||
var dialog = new openerp.base.Dialog(null, options);
|
var dialog = new openerp.base.Dialog(null, options);
|
||||||
dialog.$dialog = $(content).dialog(dialog.options);
|
dialog.$dialog = $(content).dialog(dialog.options);
|
||||||
console.log(dialog.options)
|
|
||||||
return dialog.$dialog;
|
return dialog.$dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1470,7 +1481,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||||
}, self.build_domain(),
|
}, self.build_domain(),
|
||||||
new openerp.base.CompoundContext(self.build_context(), context || {}));
|
new openerp.base.CompoundContext(self.build_context(), context || {}));
|
||||||
pop.on_select_elements.add(function(element_ids) {
|
pop.on_select_elements.add(function(element_ids) {
|
||||||
var dataset = new openerp.base.DataSetStatic(this, this.field.relation, self.build_context());
|
var dataset = new openerp.base.DataSetStatic(self, self.field.relation, self.build_context());
|
||||||
dataset.name_get([element_ids[0]], function(data) {
|
dataset.name_get([element_ids[0]], function(data) {
|
||||||
self._change_int_ext_value(data[0]);
|
self._change_int_ext_value(data[0]);
|
||||||
pop.stop();
|
pop.stop();
|
||||||
|
@ -1587,6 +1598,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||||
this.template = "FieldOne2Many";
|
this.template = "FieldOne2Many";
|
||||||
this.is_started = $.Deferred();
|
this.is_started = $.Deferred();
|
||||||
this.form_last_update = $.Deferred();
|
this.form_last_update = $.Deferred();
|
||||||
|
this.disable_utility_classes = true;
|
||||||
},
|
},
|
||||||
start: function() {
|
start: function() {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
|
@ -1632,9 +1644,16 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||||
controller.on_record_loaded.add_last(function() {
|
controller.on_record_loaded.add_last(function() {
|
||||||
once.resolve();
|
once.resolve();
|
||||||
});
|
});
|
||||||
|
controller.on_pager_action.add_first(function() {
|
||||||
|
self.save_form_view();
|
||||||
|
});
|
||||||
|
controller.$element.find(".oe_form_button_save_edit").hide();
|
||||||
}
|
}
|
||||||
self.is_started.resolve();
|
self.is_started.resolve();
|
||||||
});
|
});
|
||||||
|
this.viewmanager.on_mode_switch.add_first(function() {
|
||||||
|
self.save_form_view();
|
||||||
|
});
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
self.viewmanager.start();
|
self.viewmanager.start();
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -1704,6 +1723,9 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||||
this._super(value);
|
this._super(value);
|
||||||
this.dataset.reset_ids(value);
|
this.dataset.reset_ids(value);
|
||||||
}
|
}
|
||||||
|
if (this.dataset.index === null && this.dataset.ids.length > 0) {
|
||||||
|
this.dataset.index = 0;
|
||||||
|
}
|
||||||
$.when(this.is_started).then(function() {
|
$.when(this.is_started).then(function() {
|
||||||
self.reload_current_view();
|
self.reload_current_view();
|
||||||
});
|
});
|
||||||
|
@ -1728,9 +1750,50 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||||
this.dataset.to_delete, function(x) {
|
this.dataset.to_delete, function(x) {
|
||||||
return commands['delete'](x.id);}));
|
return commands['delete'](x.id);}));
|
||||||
},
|
},
|
||||||
|
save_form_view: function() {
|
||||||
|
if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view &&
|
||||||
|
this.viewmanager.views[this.viewmanager.active_view] &&
|
||||||
|
this.viewmanager.views[this.viewmanager.active_view].controller) {
|
||||||
|
var view = this.viewmanager.views[this.viewmanager.active_view].controller;
|
||||||
|
if (this.viewmanager.active_view === "form") {
|
||||||
|
var res = view.do_save();
|
||||||
|
if (res === false) {
|
||||||
|
// ignore
|
||||||
|
} else if (res.isRejected()) {
|
||||||
|
throw "Save or create on one2many dataset is not supposed to fail.";
|
||||||
|
} else if (!res.isResolved()) {
|
||||||
|
throw "Asynchronous get_value() is not supported in form view.";
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
is_valid: function() {
|
||||||
|
this.validate();
|
||||||
|
return this._super();
|
||||||
|
},
|
||||||
validate: function() {
|
validate: function() {
|
||||||
this.invalid = false;
|
this.invalid = false;
|
||||||
// TODO niv
|
var self = this;
|
||||||
|
var view = self.viewmanager.views[self.viewmanager.active_view].controller;
|
||||||
|
if (self.viewmanager.active_view === "form") {
|
||||||
|
for (var f in view.fields) {
|
||||||
|
f = view.fields[f];
|
||||||
|
if (!f.is_valid()) {
|
||||||
|
this.invalid = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
is_dirty: function() {
|
||||||
|
this.save_form_view();
|
||||||
|
return this._super();
|
||||||
|
},
|
||||||
|
update_dom: function() {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
this.$element.toggleClass('disabled', this.readonly);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1797,7 +1860,7 @@ openerp.base.form.FieldMany2Many = openerp.base.form.Field.extend({
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.dataset = new openerp.base.form.Many2ManyDataSet( this, this.field.relation);
|
this.dataset = new openerp.base.form.Many2ManyDataSet(this, this.field.relation);
|
||||||
this.dataset.m2m = this;
|
this.dataset.m2m = this;
|
||||||
this.dataset.on_unlink.add_last(function(ids) {
|
this.dataset.on_unlink.add_last(function(ids) {
|
||||||
self.on_ui_change();
|
self.on_ui_change();
|
||||||
|
@ -1872,7 +1935,7 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.form.SelectCreatePopup = openerp.base.BaseWidget.extend({
|
openerp.base.form.SelectCreatePopup = openerp.base.OldWidget.extend({
|
||||||
identifier_prefix: "selectcreatepopup",
|
identifier_prefix: "selectcreatepopup",
|
||||||
template: "SelectCreatePopup",
|
template: "SelectCreatePopup",
|
||||||
/**
|
/**
|
||||||
|
@ -2012,7 +2075,7 @@ openerp.base.form.SelectCreateListView = openerp.base.ListView.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.form.FormOpenPopup = openerp.base.BaseWidget.extend({
|
openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
|
||||||
identifier_prefix: "formopenpopup",
|
identifier_prefix: "formopenpopup",
|
||||||
template: "FormOpenPopup",
|
template: "FormOpenPopup",
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -28,7 +28,7 @@ openerp.base.Import = openerp.base.Dialog.extend({
|
||||||
//self.do_import();
|
//self.do_import();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
close: function(event, ui){ self.close();}
|
close: function(event, ui){ self.stop();}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -111,7 +111,6 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||||
this.columns = [];
|
this.columns = [];
|
||||||
|
|
||||||
this.options = _.extend({}, this.defaults, options || {});
|
this.options = _.extend({}, this.defaults, options || {});
|
||||||
this.flags = this.view_manager.flags || {};
|
|
||||||
|
|
||||||
this.set_groups(new openerp.base.ListView.Groups(this));
|
this.set_groups(new openerp.base.ListView.Groups(this));
|
||||||
|
|
||||||
|
@ -272,6 +271,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||||
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
||||||
this.sidebar.start();
|
this.sidebar.start();
|
||||||
this.sidebar.add_toolbar(data.fields_view.toolbar);
|
this.sidebar.add_toolbar(data.fields_view.toolbar);
|
||||||
|
this.set_common_sidebar_sections(this.sidebar);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
openerp.base.search = function(openerp) {
|
openerp.base.search = function(openerp) {
|
||||||
|
|
||||||
openerp.base.SearchView = openerp.base.Controller.extend({
|
openerp.base.SearchView = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id, dataset, view_id, defaults) {
|
init: function(parent, element_id, dataset, view_id, defaults) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
this.view_manager = parent || new openerp.base.NullViewManager();
|
||||||
|
@ -386,13 +386,13 @@ openerp.base.search.Invalid = openerp.base.Class.extend( /** @lends openerp.base
|
||||||
': [' + this.value + '] is ' + this.message);
|
': [' + 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,
|
template: null,
|
||||||
/**
|
/**
|
||||||
* Root class of all search widgets
|
* Root class of all search widgets
|
||||||
*
|
*
|
||||||
* @constructs
|
* @constructs
|
||||||
* @extends openerp.base.Controller
|
* @extends openerp.base.Widget
|
||||||
*
|
*
|
||||||
* @param view the ancestor view of this widget
|
* @param view the ancestor view of this widget
|
||||||
*/
|
*/
|
||||||
|
@ -851,7 +851,7 @@ openerp.base.search.ManyToManyField = openerp.base.search.CharField.extend({
|
||||||
// TODO: .related_columns (Array), .context, .domain
|
// 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',
|
template: 'SearchView.extended_search',
|
||||||
identifier_prefix: 'extended-search',
|
identifier_prefix: 'extended-search',
|
||||||
init: function (parent, model) {
|
init: function (parent, model) {
|
||||||
|
@ -860,9 +860,7 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
|
||||||
},
|
},
|
||||||
add_group: function() {
|
add_group: function() {
|
||||||
var group = new openerp.base.search.ExtendedSearchGroup(this, this.fields);
|
var group = new openerp.base.search.ExtendedSearchGroup(this, this.fields);
|
||||||
var render = group.render();
|
group.appendTo(this.$element.find('.searchview_extended_groups_list'));
|
||||||
this.$element.find('.searchview_extended_groups_list').append(render);
|
|
||||||
group.start();
|
|
||||||
this.check_last_element();
|
this.check_last_element();
|
||||||
},
|
},
|
||||||
start: function () {
|
start: function () {
|
||||||
|
@ -891,7 +889,7 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
|
||||||
if(this.$element.closest("table.oe-searchview-render-line").css("display") == "none") {
|
if(this.$element.closest("table.oe-searchview-render-line").css("display") == "none") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return _.reduce(this.children,
|
return _.reduce(this.widget_children,
|
||||||
function(mem, x) { return mem.concat(x.get_domain());}, []);
|
function(mem, x) { return mem.concat(x.get_domain());}, []);
|
||||||
},
|
},
|
||||||
on_activate: function() {
|
on_activate: function() {
|
||||||
|
@ -910,14 +908,14 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
check_last_element: function() {
|
check_last_element: function() {
|
||||||
_.each(this.children, function(x) {x.set_last_group(false);});
|
_.each(this.widget_children, function(x) {x.set_last_group(false);});
|
||||||
if (this.children.length >= 1) {
|
if (this.widget_children.length >= 1) {
|
||||||
this.children[this.children.length - 1].set_last_group(true);
|
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',
|
template: 'SearchView.extended_search.group',
|
||||||
identifier_prefix: 'extended-search-group',
|
identifier_prefix: 'extended-search-group',
|
||||||
init: function (parent, fields) {
|
init: function (parent, fields) {
|
||||||
|
@ -926,7 +924,7 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
||||||
},
|
},
|
||||||
add_prop: function() {
|
add_prop: function() {
|
||||||
var prop = new openerp.base.search.ExtendedSearchProposition(this, this.fields);
|
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);
|
this.$element.find('.searchview_extended_propositions_list').append(render);
|
||||||
prop.start();
|
prop.start();
|
||||||
},
|
},
|
||||||
|
@ -943,7 +941,7 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
get_domain: function() {
|
get_domain: function() {
|
||||||
var props = _(this.children).chain().map(function(x) {
|
var props = _(this.widget_children).chain().map(function(x) {
|
||||||
return x.get_proposition();
|
return x.get_proposition();
|
||||||
}).compact().value();
|
}).compact().value();
|
||||||
var choice = this.$element.find(".searchview_extended_group_choice").val();
|
var choice = this.$element.find(".searchview_extended_group_choice").val();
|
||||||
|
@ -953,9 +951,9 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
|
||||||
props);
|
props);
|
||||||
},
|
},
|
||||||
stop: function() {
|
stop: function() {
|
||||||
var parent = this.parent;
|
var parent = this.widget_parent;
|
||||||
if (this.parent.children.length == 1)
|
if (this.widget_parent.widget_children.length == 1)
|
||||||
this.parent.hide();
|
this.widget_parent.hide();
|
||||||
this._super();
|
this._super();
|
||||||
parent.check_last_element();
|
parent.check_last_element();
|
||||||
},
|
},
|
||||||
|
@ -967,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',
|
template: 'SearchView.extended_search.proposition',
|
||||||
identifier_prefix: 'extended-search-proposition',
|
identifier_prefix: 'extended-search-proposition',
|
||||||
init: function (parent, fields) {
|
init: function (parent, fields) {
|
||||||
|
@ -992,9 +990,12 @@ openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
stop: function() {
|
stop: function() {
|
||||||
if (this.parent.children.length == 1)
|
var parent;
|
||||||
this.parent.stop();
|
if (this.widget_parent.widget_children.length == 1)
|
||||||
|
parent = this.widget_parent;
|
||||||
this._super();
|
this._super();
|
||||||
|
if (parent)
|
||||||
|
parent.stop();
|
||||||
},
|
},
|
||||||
changed: function() {
|
changed: function() {
|
||||||
var nval = this.$element.find(".searchview_extended_prop_field").val();
|
var nval = this.$element.find(".searchview_extended_prop_field").val();
|
||||||
|
@ -1054,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',
|
template: 'SearchView.extended_search.proposition.char',
|
||||||
identifier_prefix: 'extended-search-proposition-char',
|
identifier_prefix: 'extended-search-proposition-char',
|
||||||
operators: [
|
operators: [
|
||||||
|
@ -1071,7 +1072,7 @@ openerp.base.search.ExtendedSearchProposition.Char = openerp.base.BaseWidget.ext
|
||||||
return this.$element.val();
|
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',
|
template: 'SearchView.extended_search.proposition.datetime',
|
||||||
identifier_prefix: 'extended-search-proposition-datetime',
|
identifier_prefix: 'extended-search-proposition-datetime',
|
||||||
operators: [
|
operators: [
|
||||||
|
@ -1093,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',
|
template: 'SearchView.extended_search.proposition.date',
|
||||||
identifier_prefix: 'extended-search-proposition-date',
|
identifier_prefix: 'extended-search-proposition-date',
|
||||||
operators: [
|
operators: [
|
||||||
|
@ -1115,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',
|
template: 'SearchView.extended_search.proposition.integer',
|
||||||
identifier_prefix: 'extended-search-proposition-integer',
|
identifier_prefix: 'extended-search-proposition-integer',
|
||||||
operators: [
|
operators: [
|
||||||
|
@ -1134,7 +1135,7 @@ openerp.base.search.ExtendedSearchProposition.Integer = openerp.base.BaseWidget.
|
||||||
return Math.round(value);
|
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',
|
template: 'SearchView.extended_search.proposition.float',
|
||||||
identifier_prefix: 'extended-search-proposition-float',
|
identifier_prefix: 'extended-search-proposition-float',
|
||||||
operators: [
|
operators: [
|
||||||
|
@ -1153,7 +1154,7 @@ openerp.base.search.ExtendedSearchProposition.Float = openerp.base.BaseWidget.ex
|
||||||
return value;
|
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',
|
template: 'SearchView.extended_search.proposition.selection',
|
||||||
identifier_prefix: 'extended-search-proposition-selection',
|
identifier_prefix: 'extended-search-proposition-selection',
|
||||||
operators: [
|
operators: [
|
||||||
|
@ -1167,7 +1168,7 @@ openerp.base.search.ExtendedSearchProposition.Selection = openerp.base.BaseWidge
|
||||||
return this.$element.val();
|
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',
|
template: 'SearchView.extended_search.proposition.boolean',
|
||||||
identifier_prefix: 'extended-search-proposition-boolean',
|
identifier_prefix: 'extended-search-proposition-boolean',
|
||||||
operators: [
|
operators: [
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
openerp.base.view_help = function(openerp) {
|
openerp.base.view_help = function(openerp) {
|
||||||
|
|
||||||
openerp.base.ProcessView = openerp.base.Controller.extend({
|
openerp.base.ProcessView = openerp.base.Widget.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.HelpView = openerp.base.Controller.extend({
|
openerp.base.HelpView = openerp.base.Widget.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
openerp.base.view_tree = function(openerp) {
|
openerp.base.view_tree = function(openerp) {
|
||||||
|
|
||||||
openerp.base.views.add('tree', 'openerp.base.TreeView');
|
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)
|
* Genuine tree view (the one displayed as a tree, not the list)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
openerp.base.views = function(openerp) {
|
openerp.base.views = function(openerp) {
|
||||||
|
|
||||||
openerp.base.ActionManager = openerp.base.Controller.extend({
|
openerp.base.ActionManager = openerp.base.Widget.extend({
|
||||||
// process all kind of actions
|
// process all kind of actions
|
||||||
init: function(parent, element_id) {
|
init: function(parent, element_id) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
|
@ -98,18 +98,21 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
||||||
|
|
||||||
openerp.base.ActionDialog = openerp.base.Dialog.extend({
|
openerp.base.ActionDialog = openerp.base.Dialog.extend({
|
||||||
identifier_prefix: 'action_dialog',
|
identifier_prefix: 'action_dialog',
|
||||||
stop: function() {
|
on_close: function() {
|
||||||
this._super(this, arguments);
|
this._super(this, arguments);
|
||||||
if (this.close_callback) {
|
if (this.close_callback) {
|
||||||
this.close_callback();
|
this.close_callback();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
stop: function() {
|
||||||
|
this._super(this, arguments);
|
||||||
if (this.viewmanager) {
|
if (this.viewmanager) {
|
||||||
this.viewmanager.stop();
|
this.viewmanager.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.ViewManager = openerp.base.Controller.extend({
|
openerp.base.ViewManager = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id, dataset, views) {
|
init: function(parent, element_id, dataset, views) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.model = dataset.model;
|
this.model = dataset.model;
|
||||||
|
@ -126,6 +129,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
||||||
* @returns {jQuery.Deferred} initial view loading promise
|
* @returns {jQuery.Deferred} initial view loading promise
|
||||||
*/
|
*/
|
||||||
start: function() {
|
start: function() {
|
||||||
|
this._super();
|
||||||
var self = this;
|
var self = this;
|
||||||
this.dataset.start();
|
this.dataset.start();
|
||||||
this.$element.html(QWeb.render("ViewManager", {"prefix": this.element_id, views: this.views_src}));
|
this.$element.html(QWeb.render("ViewManager", {"prefix": this.element_id, views: this.views_src}));
|
||||||
|
@ -343,7 +347,7 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
stop: function() {
|
stop: function() {
|
||||||
// should be replaced by automatic destruction implemented in BaseWidget
|
// should be replaced by automatic destruction implemented in Widget
|
||||||
this._super();
|
this._super();
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -370,10 +374,11 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Sidebar = openerp.base.Controller.extend({
|
openerp.base.Sidebar = openerp.base.Widget.extend({
|
||||||
init: function(parent, element_id) {
|
init: function(parent, element_id) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.items = {};
|
this.items = {};
|
||||||
|
this.sections = {};
|
||||||
},
|
},
|
||||||
start: function() {
|
start: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -395,11 +400,11 @@ openerp.base.Sidebar = openerp.base.Controller.extend({
|
||||||
classname: 'oe_sidebar_' + type[0]
|
classname: 'oe_sidebar_' + type[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.add_section(type[1], items);
|
self.add_section(type[0], type[1], items);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
add_section: function(name, items) {
|
add_section: function(code, name, items) {
|
||||||
// For each section, we pass a name/label and optionally an array of 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
|
// 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.
|
// returning back an element_id to be used by a custom controller.
|
||||||
|
@ -408,11 +413,12 @@ openerp.base.Sidebar = openerp.base.Controller.extend({
|
||||||
// label: label to be displayed for the link,
|
// label: label to be displayed for the link,
|
||||||
// action: action to be launch when the link is clicked,
|
// action: action to be launch when the link is clicked,
|
||||||
// callback: a function to be executed when the link is clicked,
|
// callback: a function to be executed when the link is clicked,
|
||||||
// classname: optionnal dom class name for the line,
|
// 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
|
// Note: The item should have one action or/and a callback
|
||||||
var self = this,
|
var self = this,
|
||||||
section_id = _.uniqueId(this.element_id + '_section_');
|
section_id = _.uniqueId(this.element_id + '_section_' + code + '_');
|
||||||
if (items) {
|
if (items) {
|
||||||
for (var i = 0; i < items.length; i++) {
|
for (var i = 0; i < items.length; i++) {
|
||||||
items[i].element_id = _.uniqueId(section_id + '_item_');
|
items[i].element_id = _.uniqueId(section_id + '_item_');
|
||||||
|
@ -422,6 +428,7 @@ openerp.base.Sidebar = openerp.base.Controller.extend({
|
||||||
var $section = $(QWeb.render("Sidebar.section", {
|
var $section = $(QWeb.render("Sidebar.section", {
|
||||||
section_id: section_id,
|
section_id: section_id,
|
||||||
name: name,
|
name: name,
|
||||||
|
classname: 'oe_sidebar_' + code,
|
||||||
items: items
|
items: items
|
||||||
}));
|
}));
|
||||||
if (items) {
|
if (items) {
|
||||||
|
@ -439,6 +446,7 @@ openerp.base.Sidebar = openerp.base.Controller.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$section.appendTo(this.$element.find('div.sidebar-actions'));
|
$section.appendTo(this.$element.find('div.sidebar-actions'));
|
||||||
|
this.sections[code] = $section;
|
||||||
return section_id;
|
return section_id;
|
||||||
},
|
},
|
||||||
do_fold: function() {
|
do_fold: function() {
|
||||||
|
@ -452,26 +460,7 @@ openerp.base.Sidebar = openerp.base.Controller.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.base.Export = openerp.base.Dialog.extend({
|
openerp.base.View = openerp.base.Widget.extend({
|
||||||
dialog_title: "Export",
|
|
||||||
template: 'ExportDialog',
|
|
||||||
identifier_prefix: 'export_dialog',
|
|
||||||
init: function (session, model, domain) {
|
|
||||||
this._super();
|
|
||||||
},
|
|
||||||
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({
|
|
||||||
set_default_options: function(options) {
|
set_default_options: function(options) {
|
||||||
this.options = options || {};
|
this.options = options || {};
|
||||||
_.defaults(this.options, {
|
_.defaults(this.options, {
|
||||||
|
@ -540,6 +529,60 @@ openerp.base.View = openerp.base.Controller.extend({
|
||||||
*/
|
*/
|
||||||
set_embedded_view: function(embedded_view) {
|
set_embedded_view: function(embedded_view) {
|
||||||
this.embedded_view = 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() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,23 +19,31 @@
|
||||||
</div>
|
</div>
|
||||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" class="main_table">
|
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" class="main_table">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2" valign="top">
|
||||||
<div id="oe_header" class="header"></div>
|
<div id="oe_header" class="header"></div>
|
||||||
<div id="oe_menu" class="menu"></div>
|
<div id="oe_menu" class="menu"></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" id="oe_secondary_menu" class="secondary_menu">
|
<td valign="top" class="login-container" colspan="2">
|
||||||
|
<div id="oe_login" class="login"></div>
|
||||||
</td>
|
</td>
|
||||||
<td valign="top" >
|
</tr>
|
||||||
<div id="oe_app" class="oe-application">
|
<tr class="db_options_row">
|
||||||
<div style="width:100%;">&nbsp;</div>
|
<td valign="top" class="db_container">
|
||||||
</div>
|
<div id="oe_database" class="database"></div>
|
||||||
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<div id="oe_db_options"></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" class="login-container" colspan="2">
|
<td valign="top" id="oe_secondary_menu" class="secondary_menu">
|
||||||
<div id="oe_login" class="login"></div>
|
</td>
|
||||||
|
<td valign="top">
|
||||||
|
<div id="oe_app" class="oe-application">
|
||||||
|
<div style="width: 100%;">&nbsp;</div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -50,6 +58,188 @@
|
||||||
<t t-name="Loading">
|
<t t-name="Loading">
|
||||||
Loading...
|
Loading...
|
||||||
</t>
|
</t>
|
||||||
|
<t t-name="Database">
|
||||||
|
<ul class="db_options" style="padding: 0px; display: inline;">
|
||||||
|
<li id="db-create">Create</li>
|
||||||
|
<li id="db-drop">Drop</li>
|
||||||
|
<li id="db-backup">Backup</li>
|
||||||
|
<li id="db-restore">Restore</li>
|
||||||
|
<li id="db-change-password">Password</li>
|
||||||
|
<li id="back-to-login">Back to Login</li>
|
||||||
|
</ul>
|
||||||
|
</t>
|
||||||
|
<t t-name="CreateDB">
|
||||||
|
<form name="create_db_form" method="POST">
|
||||||
|
<table width="100%">
|
||||||
|
<tr>
|
||||||
|
<td class="option_string">
|
||||||
|
CREATE DATABASE
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table align="center" class="db_option_table">
|
||||||
|
<tr>
|
||||||
|
<td><label for="super_admin_pwd">Super admin password:</label></td>
|
||||||
|
<td><input type="password" name="super_admin_pwd"
|
||||||
|
class="required" autofocus="autofocus"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="db_name">New database name:</label></td>
|
||||||
|
<td><input type="text" name="db_name" class="required"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="demo_data">Load Demonstration data:</label></td>
|
||||||
|
<td><input type="checkbox" name="demo_data" checked='checked'/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="db_lang">Default language:</label></td>
|
||||||
|
<td>
|
||||||
|
<select name="db_lang" t-if="lang_list">
|
||||||
|
<t t-foreach="lang_list" t-as="lang">
|
||||||
|
<option t-att-value="lang[0]"
|
||||||
|
t-att-selected="lang[0] === 'en_US' ? 'selected' : undefined">
|
||||||
|
<t t-esc="lang[1]"/></option>
|
||||||
|
</t>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="create_admin_pwd">Super admin password:</label></td>
|
||||||
|
<td><input type="password" name="create_admin_pwd" class="required"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="create_confirm_pwd">Confirm password:</label></td>
|
||||||
|
<td><input type="password" name="create_confirm_pwd" class="required"
|
||||||
|
equalTo="input[name=create_admin_pwd]"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="right"><input type="submit" value="Create"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</t>
|
||||||
|
<t t-name="DropDB">
|
||||||
|
<form name="drop_db_form" method="POST">
|
||||||
|
<table width="100%">
|
||||||
|
<tr>
|
||||||
|
<td class="option_string">
|
||||||
|
DROP DATABASE
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table align="center" class="db_option_table">
|
||||||
|
<tr>
|
||||||
|
<td><label for="drop_db">Database:</label></td>
|
||||||
|
<td>
|
||||||
|
<select t-if="db_list" name="drop_db" autofocus="autofocus">
|
||||||
|
<t t-foreach="db_list" t-as="db">
|
||||||
|
<option t-att-value="db"><t t-esc="db"/></option>
|
||||||
|
</t>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="drop_password">Password:</label></td>
|
||||||
|
<td><input type="password" name="drop_pwd" class="required"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="right"><input type="submit" value="Drop"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</t>
|
||||||
|
<t t-name="BackupDB">
|
||||||
|
<form name="backup_db_form" method="POST" target="backup-target"
|
||||||
|
action="/base/database/backup">
|
||||||
|
<input type="hidden" name="token"/>
|
||||||
|
<table width="100%">
|
||||||
|
<tr>
|
||||||
|
<td class="option_string">
|
||||||
|
BACKUP DATABASE
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table align="center" class="db_option_table">
|
||||||
|
<tr>
|
||||||
|
<td><label for="backup_db">Database:</label></td>
|
||||||
|
<td>
|
||||||
|
<select t-if="db_list" name="backup_db" autofocus="autofocus">
|
||||||
|
<t t-foreach="db_list" t-as="db">
|
||||||
|
<option t-att-value="db"><t t-esc="db"/></option>
|
||||||
|
</t>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="backup_pwd">Password:</label></td>
|
||||||
|
<td><input type="password" name="backup_pwd" class="required"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="right"><input type="submit" value="Backup"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</t>
|
||||||
|
<t t-name="RestoreDB">
|
||||||
|
<form name="restore_db_form" method="POST">
|
||||||
|
<table width="100%">
|
||||||
|
<tr>
|
||||||
|
<td class="option_string">
|
||||||
|
RESTORE DATABASE
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table align="center" class="db_option_table">
|
||||||
|
<tr>
|
||||||
|
<td><label for="restore_db">File:</label></td>
|
||||||
|
<td><input type="file" name="db_file" class="required"
|
||||||
|
autofocus="autofocus"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="restore_pwd">Password:</label></td>
|
||||||
|
<td><input type="password" name="restore_pwd" class="required"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="new_db">New database name:</label></td>
|
||||||
|
<td><input type="text" name="new_db" class="required"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="right"><input type="submit" value="Restore"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</t>
|
||||||
|
<t t-name="Change_DB_Pwd">
|
||||||
|
<form name="change_pwd_form" method="POST">
|
||||||
|
<table width="100%">
|
||||||
|
<tr>
|
||||||
|
<td class="option_string">
|
||||||
|
CHANGE DATABASE PASSWORD
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table align="center" class="db_option_table">
|
||||||
|
<tr>
|
||||||
|
<td><label for="old_pwd">Old password:</label></td>
|
||||||
|
<td><input type="password" name="old_pwd" class="required"
|
||||||
|
minlength="1" autofocus="autofocus"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="new_pwd">New password:</label></td>
|
||||||
|
<td><input type="password" name="new_pwd" class="required"
|
||||||
|
minlength="1"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="confirm_pwd">Confirm password:</label></td>
|
||||||
|
<td><input type="password" name="confirm_pwd" class="required"
|
||||||
|
equalTo="input[name=new_pwd]" minlength="1"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="right"><input type="submit" value="Change Password"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</t>
|
||||||
<t t-name="Login">
|
<t t-name="Login">
|
||||||
<form>
|
<form>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
@ -92,6 +282,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>
|
<td>
|
||||||
|
<button type="button" id="oe-db-config">Database</button>
|
||||||
<button type="submit" name="submit">Login</button>
|
<button type="submit" name="submit">Login</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -248,10 +439,10 @@
|
||||||
</t>
|
</t>
|
||||||
<t t-name="Sidebar.section">
|
<t t-name="Sidebar.section">
|
||||||
<h2><t t-esc="name"/></h2>
|
<h2><t t-esc="name"/></h2>
|
||||||
<div t-att-id="section_id">
|
<div t-att-id="section_id" t-att-class="classname">
|
||||||
<ul t-if="items">
|
<ul t-if="items">
|
||||||
<li t-foreach="items" t-as="item" t-att-class="item.classname">
|
<li t-foreach="items" t-as="item" t-att-class="item.classname">
|
||||||
<a class="oe_sidebar_action_a" t-att-id="item.element_id" href="#">
|
<a class="oe_sidebar_action_a" t-att-id="item.element_id" t-att-title="item.title" href="#">
|
||||||
<t t-esc="item.label"/>
|
<t t-esc="item.label"/>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -261,11 +452,11 @@
|
||||||
<table t-name="ListView" class="oe-listview-content">
|
<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="columns_count" t-value="visible_columns.length + (options.selectable ? 1 : 0) + (options.deletable ? 1 : 0)"/>
|
||||||
<thead class="ui-widget-header">
|
<thead class="ui-widget-header">
|
||||||
<tr t-if="flags.action_buttons !== false or flags.pager !== false">
|
<tr t-if="options.action_buttons !== false or options.pager !== false">
|
||||||
<th t-att-colspan="columns_count">
|
<th t-att-colspan="columns_count">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td t-if="flags.action_buttons !== false" class="oe-actions">
|
<td t-if="options.action_buttons !== false" class="oe-actions">
|
||||||
<button type="button" class="oe-list-add"
|
<button type="button" class="oe-list-add"
|
||||||
t-if="options.addable">
|
t-if="options.addable">
|
||||||
<t t-esc="options.addable"/>
|
<t t-esc="options.addable"/>
|
||||||
|
@ -275,7 +466,7 @@
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<th t-if="flags.pager !== false" class="oe-list-pager">
|
<th t-if="options.pager !== false" class="oe-list-pager">
|
||||||
<button type="button" disabled="disabled"
|
<button type="button" disabled="disabled"
|
||||||
data-pager-action="first">First</button>
|
data-pager-action="first">First</button>
|
||||||
<button type="button" disabled="disabled"
|
<button type="button" disabled="disabled"
|
||||||
|
@ -357,7 +548,7 @@
|
||||||
<t t-name="FormView">
|
<t t-name="FormView">
|
||||||
<div class="oe_form_header" t-att-id="view.element_id + '_header'">
|
<div class="oe_form_header" t-att-id="view.element_id + '_header'">
|
||||||
<h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/> <button class="oe_get_xml_view">xml</button></h2>
|
<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.flags.action_buttons !== false">
|
<div class="oe_form_buttons" t-if="view.options.action_buttons !== false">
|
||||||
<!--<button type="button" class="oe_form_button_save">
|
<!--<button type="button" class="oe_form_button_save">
|
||||||
<span class="oe_form_on_update">Save</span>
|
<span class="oe_form_on_update">Save</span>
|
||||||
<span class="oe_form_on_create">Create</span>
|
<span class="oe_form_on_create">Create</span>
|
||||||
|
@ -369,7 +560,7 @@
|
||||||
<!--<button type="button" class="oe_form_button_cancel">Cancel</button>-->
|
<!--<button type="button" class="oe_form_button_cancel">Cancel</button>-->
|
||||||
<button type="button" class="oe_form_button_new">New</button>
|
<button type="button" class="oe_form_button_new">New</button>
|
||||||
</div>
|
</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="first">First</button>
|
||||||
<button type="button" data-pager-action="previous"><<</button>
|
<button type="button" data-pager-action="previous"><<</button>
|
||||||
|
|
||||||
|
@ -944,6 +1135,147 @@
|
||||||
.unwrap();
|
.unwrap();
|
||||||
</t>
|
</t>
|
||||||
</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>
|
||||||
<t t-name="ImportView">
|
<t t-name="ImportView">
|
||||||
<a id="importview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Import</a>
|
<a id="importview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Import</a>
|
||||||
</t>
|
</t>
|
||||||
|
|
|
@ -18,15 +18,6 @@ $(document).ready(function () {
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
var fuck_that_shit = {
|
|
||||||
action: {
|
|
||||||
flags: {}
|
|
||||||
},
|
|
||||||
sidebar: {
|
|
||||||
set_toolbar: function () {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var openerp;
|
var openerp;
|
||||||
module("ListView", {
|
module("ListView", {
|
||||||
setup: function () {
|
setup: function () {
|
||||||
|
@ -42,8 +33,7 @@ $(document).ready(function () {
|
||||||
|
|
||||||
test('render selection checkboxes', 2, function () {
|
test('render selection checkboxes', 2, function () {
|
||||||
var listview = new openerp.base.ListView(
|
var listview = new openerp.base.ListView(
|
||||||
fuck_that_shit, null,
|
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
||||||
'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
|
||||||
|
|
||||||
listview.on_loaded(fvg);
|
listview.on_loaded(fvg);
|
||||||
|
|
||||||
|
@ -60,8 +50,7 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
test('render no checkbox if selectable=false', 1, function () {
|
test('render no checkbox if selectable=false', 1, function () {
|
||||||
var listview = new openerp.base.ListView(
|
var listview = new openerp.base.ListView(
|
||||||
fuck_that_shit, null,
|
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0}, false,
|
||||||
'qunit-fixture', {model: null, ids: [null, null, null], index: 0}, false,
|
|
||||||
{selectable: false});
|
{selectable: false});
|
||||||
|
|
||||||
listview.on_loaded(fvg);
|
listview.on_loaded(fvg);
|
||||||
|
@ -75,8 +64,7 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
test('select a bunch of records', 2, function () {
|
test('select a bunch of records', 2, function () {
|
||||||
var listview = new openerp.base.ListView(
|
var listview = new openerp.base.ListView(
|
||||||
fuck_that_shit, null, 'qunit-fixture',
|
null, 'qunit-fixture', {model: null, ids: [1, 2, 3], index: 0});
|
||||||
{model: null, ids: [1, 2, 3], index: 0});
|
|
||||||
listview.on_loaded(fvg);
|
listview.on_loaded(fvg);
|
||||||
|
|
||||||
listview.do_fill_table({records: [
|
listview.do_fill_table({records: [
|
||||||
|
@ -94,8 +82,7 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
test('render deletion button if list is deletable', 1, function () {
|
test('render deletion button if list is deletable', 1, function () {
|
||||||
var listview = new openerp.base.ListView(
|
var listview = new openerp.base.ListView(
|
||||||
fuck_that_shit, null, 'qunit-fixture',
|
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
||||||
{model: null, ids: [null, null, null], index: 0});
|
|
||||||
|
|
||||||
listview.on_loaded(fvg);
|
listview.on_loaded(fvg);
|
||||||
|
|
||||||
|
@ -112,7 +99,7 @@ $(document).ready(function () {
|
||||||
2, function () {
|
2, function () {
|
||||||
var deleted;
|
var deleted;
|
||||||
var listview = new openerp.base.ListView(
|
var listview = new openerp.base.ListView(
|
||||||
fuck_that_shit, null, 'qunit-fixture',
|
null, 'qunit-fixture',
|
||||||
{model: null, unlink: function (ids) {
|
{model: null, unlink: function (ids) {
|
||||||
deleted = ids;
|
deleted = ids;
|
||||||
}, ids: [1, 2, 3], index: 0});
|
}, ids: [1, 2, 3], index: 0});
|
||||||
|
@ -132,7 +119,7 @@ $(document).ready(function () {
|
||||||
test('multiple records deletion', 1, function () {
|
test('multiple records deletion', 1, function () {
|
||||||
var deleted;
|
var deleted;
|
||||||
var listview = new openerp.base.ListView(
|
var listview = new openerp.base.ListView(
|
||||||
fuck_that_shit, null, 'qunit-fixture',
|
null, 'qunit-fixture',
|
||||||
{model: null, unlink: function (ids) {
|
{model: null, unlink: function (ids) {
|
||||||
deleted = ids;
|
deleted = ids;
|
||||||
}, ids: [1, 2, 3], index: 0});
|
}, ids: [1, 2, 3], index: 0});
|
||||||
|
|
|
@ -1,56 +1,14 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"name" : "Basic Calendar Functionality",
|
"name": "Base calendar",
|
||||||
"version" : "1.0",
|
"version": "2.0",
|
||||||
"depends" : ["base"],
|
"depends": ['base'],
|
||||||
'complexity': "easy",
|
"js": [
|
||||||
'description': """
|
'static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.js',
|
||||||
This is a full-featured calendar system.
|
'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js',
|
||||||
========================================
|
'static/src/js/calendar.js'
|
||||||
|
|
||||||
It supports:
|
|
||||||
- Calendar of events
|
|
||||||
- Alerts (create requests)
|
|
||||||
- Recurring events
|
|
||||||
- Invitations to people""",
|
|
||||||
"author" : "OpenERP SA",
|
|
||||||
'category': 'Tools',
|
|
||||||
'website': 'http://www.openerp.com',
|
|
||||||
"init_xml" : [
|
|
||||||
'base_calendar_data.xml'
|
|
||||||
],
|
],
|
||||||
"demo_xml" : [],
|
"css": ['static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.css',
|
||||||
"update_xml" : [
|
'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_ext.css'
|
||||||
'security/calendar_security.xml',
|
|
||||||
'security/ir.model.access.csv',
|
|
||||||
'wizard/base_calendar_invite_attendee_view.xml',
|
|
||||||
'base_calendar_view.xml'
|
|
||||||
],
|
],
|
||||||
"test" : ['test/base_calendar_test.yml'],
|
'active': True
|
||||||
"installable" : True,
|
|
||||||
"active" : False,
|
|
||||||
"certificate" : "00694071962960352821",
|
|
||||||
'images': ['images/base_calendar1.jpeg','images/base_calendar2.jpeg','images/base_calendar3.jpeg','images/base_calendar4.jpeg',],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
||||||
|
|
|
@ -1,356 +1,10 @@
|
||||||
from base.controllers.main import View
|
from base.controllers.main import View
|
||||||
import openerpweb, time, math, re, datetime as DT, pytz
|
import openerpweb
|
||||||
|
|
||||||
COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
|
|
||||||
'#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
|
|
||||||
'#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
|
|
||||||
'#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900', ]
|
|
||||||
|
|
||||||
_colorline = ['#%02x%02x%02x' % (25 + ((r + 10) % 11) * 23, 5 + ((g + 1) % 11) * 20, 25 + ((b + 4) % 11) * 23) for r in range(11) for g in range(11) for b in range(11) ]
|
|
||||||
|
|
||||||
DT_SERVER_FORMATS = {
|
|
||||||
'datetime' : '%Y-%m-%d %H:%M:%S',
|
|
||||||
'date' : '%Y-%m-%d',
|
|
||||||
'time' : '%H:%M:%S'
|
|
||||||
}
|
|
||||||
|
|
||||||
DT_FORMAT_INFO = {'datetime' : ('%Y-%m-%d %H:%M:%S', DT.datetime, 0, 6),
|
|
||||||
'date': ('%Y-%m-%d', DT.date, 0, 3),
|
|
||||||
'time': ('%H:%M:%S', DT.time, 3, 6)}
|
|
||||||
|
|
||||||
def choice_colors(n):
|
|
||||||
if n > len(COLOR_PALETTE):
|
|
||||||
return _colorline[0:-1:len(_colorline) / (n + 1)]
|
|
||||||
elif n:
|
|
||||||
return COLOR_PALETTE[:n]
|
|
||||||
return []
|
|
||||||
|
|
||||||
class CalendarView(View):
|
class CalendarView(View):
|
||||||
_cp_path = "/base_calendar/calendarview"
|
_cp_path = "/base_calendar/calendarview"
|
||||||
|
|
||||||
mode = 'month'
|
|
||||||
date_start = None
|
|
||||||
date_delay = None
|
|
||||||
date_stop = None
|
|
||||||
color_field = None
|
|
||||||
day_length = 8
|
|
||||||
use_search = False
|
|
||||||
selected_day = None
|
|
||||||
date_format = '%Y-%m-%d'
|
|
||||||
info_fields = []
|
|
||||||
fields = {}
|
|
||||||
events = []
|
|
||||||
|
|
||||||
colors = {}
|
|
||||||
color_values = []
|
|
||||||
|
|
||||||
remote_timezone = 'utc'
|
|
||||||
client_timezone = False
|
|
||||||
|
|
||||||
calendar_fields = {}
|
|
||||||
concurrency_info = None
|
|
||||||
|
|
||||||
ids = []
|
|
||||||
model = ''
|
|
||||||
domain = []
|
|
||||||
context = {}
|
|
||||||
|
|
||||||
@openerpweb.jsonrequest
|
@openerpweb.jsonrequest
|
||||||
def load(self, req, model, view_id):
|
def load(self, req, model, view_id, toolbar=False):
|
||||||
fields_view = self.fields_view_get(req, model, view_id, 'calendar')
|
fields_view = self.fields_view_get(req, model, view_id, 'calendar', toolbar=toolbar)
|
||||||
return {'fields_view':fields_view}
|
return {'fields_view': fields_view}
|
||||||
|
|
||||||
def convert(self, event):
|
|
||||||
fields = [self.date_start]
|
|
||||||
if self.date_stop:
|
|
||||||
fields.append(self.date_stop)
|
|
||||||
|
|
||||||
for fld in fields:
|
|
||||||
fld_type = self.fields[fld]['type']
|
|
||||||
fmt = DT_SERVER_FORMATS[fld_type]
|
|
||||||
if event[fld] and fmt:
|
|
||||||
event[fld] = time.strptime(event[fld], fmt)
|
|
||||||
|
|
||||||
# default start/stop time is 9:00 AM / 5:00 PM
|
|
||||||
if fld_type == 'date' and event[fld]:
|
|
||||||
ds = list(event[fld])
|
|
||||||
if fld == self.date_start:
|
|
||||||
ds[3] = 9
|
|
||||||
elif fld == self.date_stop:
|
|
||||||
ds[3] = 17
|
|
||||||
event[fld] = tuple(ds)
|
|
||||||
|
|
||||||
|
|
||||||
@openerpweb.jsonrequest
|
|
||||||
def schedule_events(self, req, **kw):
|
|
||||||
self.model = kw['model']
|
|
||||||
self.mode = kw.get('mode') or self.mode or 'month'
|
|
||||||
self.fields = kw['fields']
|
|
||||||
self.color_field = kw.get('color_field') or self.color_field or None
|
|
||||||
self.colors = kw.get('colors') or {}
|
|
||||||
self.calendar_fields = kw['calendar_fields']
|
|
||||||
self.info_fields = kw['info_fields']
|
|
||||||
self.date_start = self.calendar_fields['date_start']['name']
|
|
||||||
self.domain = kw.get('domain') or []
|
|
||||||
|
|
||||||
self.remote_timezone = req.session.remote_timezone
|
|
||||||
self.client_timezone = req.session.client_timezone
|
|
||||||
|
|
||||||
if self.calendar_fields.get('date_stop'):
|
|
||||||
self.date_stop = self.calendar_fields['date_stop']['name']
|
|
||||||
|
|
||||||
if self.calendar_fields.get('date_delay'):
|
|
||||||
self.date_delay = self.calendar_fields['date_delay']['name']
|
|
||||||
|
|
||||||
model = req.session.model(self.model)
|
|
||||||
event_ids = model.search(self.domain)
|
|
||||||
|
|
||||||
self.events = model.read(event_ids, self.fields.keys())
|
|
||||||
result = []
|
|
||||||
self.date_format = req.session._lang and req.session._lang['date_format']
|
|
||||||
|
|
||||||
if self.color_field:
|
|
||||||
for evt in self.events:
|
|
||||||
key = evt[self.color_field]
|
|
||||||
name = key
|
|
||||||
value = key
|
|
||||||
if isinstance(key, list): # M2O, XMLRPC returns List instead of Tuple
|
|
||||||
name = key[0]
|
|
||||||
value = key[-1]
|
|
||||||
evt[self.color_field] = key = key[-1]
|
|
||||||
if isinstance(key, tuple): # M2O
|
|
||||||
value, name = key
|
|
||||||
self.colors[key] = (name, value, None)
|
|
||||||
|
|
||||||
colors = choice_colors(len(self.colors))
|
|
||||||
for i, (key, value) in enumerate(self.colors.items()):
|
|
||||||
self.colors[key] = [value[0], value[1], colors[i]]
|
|
||||||
|
|
||||||
for evt in self.events:
|
|
||||||
self.convert(evt)
|
|
||||||
a = self.get_event_widget(evt)
|
|
||||||
result.append(a)
|
|
||||||
|
|
||||||
return {'result':result,'sidebar':self.colors}
|
|
||||||
|
|
||||||
def parsedatetime(self, string):
|
|
||||||
|
|
||||||
kind = 'datetime'
|
|
||||||
|
|
||||||
if '-' in string and ':' in string:
|
|
||||||
kind = 'datetime'
|
|
||||||
elif '-' in string:
|
|
||||||
kind = 'date'
|
|
||||||
elif ':' in string:
|
|
||||||
kind = 'time'
|
|
||||||
|
|
||||||
fmt, obj, i, j = DT_FORMAT_INFO[kind]
|
|
||||||
return obj(*time.strptime(string, fmt)[i:j])
|
|
||||||
|
|
||||||
def parse_datetime(self, value, kind="datetime", as_timetuple=False):
|
|
||||||
server_format = DT_SERVER_FORMATS[kind]
|
|
||||||
local_format = self.date_format
|
|
||||||
if not value:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if isinstance(value, (time.struct_time, tuple)):
|
|
||||||
value = time.strftime(local_format, value)
|
|
||||||
|
|
||||||
try:
|
|
||||||
value = time.strptime(value, local_format)
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
# might be in server format already (e.g. filter domain)
|
|
||||||
value = time.strptime(value, server_format)
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
dt = list(time.localtime())
|
|
||||||
dt[2] = int(value)
|
|
||||||
value = tuple(dt)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if kind == "datetime":
|
|
||||||
try:
|
|
||||||
value = self.tz_convert(value, 'parse')
|
|
||||||
except Exception,e:
|
|
||||||
print "*******************Error in timezone parsing *********",e
|
|
||||||
|
|
||||||
if as_timetuple:
|
|
||||||
return value
|
|
||||||
|
|
||||||
return time.strftime(server_format, value)
|
|
||||||
|
|
||||||
|
|
||||||
@openerpweb.jsonrequest
|
|
||||||
def edit_events(self, req,**kw):
|
|
||||||
data = {}
|
|
||||||
ds = self.parsedatetime(kw['start_date'])
|
|
||||||
de = self.parsedatetime(kw['end_date'])
|
|
||||||
data[kw['calendar_fields']['date_start']['name']] = self.parse_datetime(ds.timetuple())
|
|
||||||
|
|
||||||
if 'date_stop' in kw['calendar_fields']:
|
|
||||||
data[kw['calendar_fields']['date_stop']['name']] = self.parse_datetime(de.timetuple())
|
|
||||||
elif 'date_delay' in kw['calendar_fields']:
|
|
||||||
day_length = kw['calendar_fields']['day_length']
|
|
||||||
|
|
||||||
tds = time.mktime(ds.timetuple())
|
|
||||||
tde = time.mktime(de.timetuple())
|
|
||||||
|
|
||||||
n = (tde - tds) / (60 * 60)
|
|
||||||
|
|
||||||
if n > day_length:
|
|
||||||
d = math.floor(n / 24)
|
|
||||||
h = n % 24
|
|
||||||
|
|
||||||
n = d * day_length + h
|
|
||||||
|
|
||||||
data[kw['calendar_fields']['date_delay']['name']] = n
|
|
||||||
error = None
|
|
||||||
try:
|
|
||||||
req.session.model(kw['model']).write([int(kw['id'])], data)
|
|
||||||
except Exception, e:
|
|
||||||
error = e
|
|
||||||
return error
|
|
||||||
|
|
||||||
def tz_convert(self, struct_time, action):
|
|
||||||
# if no client timezone is configured, consider the client is in the same
|
|
||||||
# timezone as the server
|
|
||||||
lzone = pytz.timezone(self.client_timezone or self.remote_timezone)
|
|
||||||
szone = pytz.timezone(self.remote_timezone)
|
|
||||||
dt = DT.datetime.fromtimestamp(time.mktime(struct_time))
|
|
||||||
|
|
||||||
if action == 'parse':
|
|
||||||
fromzone = lzone
|
|
||||||
tozone = szone
|
|
||||||
elif action == 'format':
|
|
||||||
fromzone = szone
|
|
||||||
tozone = lzone
|
|
||||||
else:
|
|
||||||
raise Exception("_tz_convert action should be 'parse' or 'format'. Not '%s'" % (action, ))
|
|
||||||
|
|
||||||
localized_original_datetime = fromzone.localize(dt, is_dst=True)
|
|
||||||
destination_datetime = localized_original_datetime.astimezone(tozone)
|
|
||||||
return destination_datetime.timetuple()
|
|
||||||
|
|
||||||
def format_datetime(self, value, kind="datetime", as_timetuple=False):
|
|
||||||
"""Convert date value to the local datetime considering timezone info.
|
|
||||||
|
|
||||||
@param value: the date value
|
|
||||||
@param kind: type of the date value (date, time or datetime)
|
|
||||||
@param as_timetuple: return timetuple
|
|
||||||
|
|
||||||
@type value: basestring or time.time_tuple)
|
|
||||||
|
|
||||||
@return: string or timetuple
|
|
||||||
"""
|
|
||||||
|
|
||||||
server_format = DT_SERVER_FORMATS[kind]
|
|
||||||
local_format = self.date_format
|
|
||||||
|
|
||||||
if not value:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
if isinstance(value, (time.struct_time, tuple)):
|
|
||||||
value = time.strftime(server_format, value)
|
|
||||||
|
|
||||||
if isinstance(value, DT.datetime):
|
|
||||||
value = value
|
|
||||||
try:
|
|
||||||
value = DT.datetime.strptime(value[:10], server_format)
|
|
||||||
return value.strftime(local_format)
|
|
||||||
except:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
value = value.strip()
|
|
||||||
|
|
||||||
# remove trailing miliseconds
|
|
||||||
value = re.sub("(.*?)(\s+\d{2}:\d{2}:\d{2})(\.\d+)?$", "\g<1>\g<2>", value)
|
|
||||||
|
|
||||||
# add time part in value if missing
|
|
||||||
if kind == 'datetime' and not re.search('\s+\d{2}:\d{2}:\d{2}?$', value):
|
|
||||||
value += ' 00:00:00'
|
|
||||||
|
|
||||||
# remove time part from value
|
|
||||||
elif kind == 'date':
|
|
||||||
value = re.sub('\s+\d{2}:\d{2}:\d{2}(\.\d+)?$', '', value)
|
|
||||||
|
|
||||||
value = time.strptime(value, server_format)
|
|
||||||
|
|
||||||
if kind == "datetime":
|
|
||||||
try:
|
|
||||||
value = self.tz_convert(value, 'format')
|
|
||||||
except Exception, e:
|
|
||||||
print "\n\n\n************ Error in timezone formatting", e
|
|
||||||
|
|
||||||
if as_timetuple:
|
|
||||||
return value
|
|
||||||
|
|
||||||
return time.strftime(local_format, value)
|
|
||||||
|
|
||||||
def get_event_widget(self, event):
|
|
||||||
title = '' # the title
|
|
||||||
description = [] # the description
|
|
||||||
|
|
||||||
if self.info_fields:
|
|
||||||
|
|
||||||
f = self.info_fields[0]
|
|
||||||
s = event[f]
|
|
||||||
|
|
||||||
if isinstance(s, (tuple, list)): s = s[-1]
|
|
||||||
|
|
||||||
title = s
|
|
||||||
for f in self.info_fields[1:]:
|
|
||||||
s = event[f]
|
|
||||||
if isinstance(s, (tuple, list)):
|
|
||||||
s = s[-1]
|
|
||||||
if s:
|
|
||||||
description.append(str(s))
|
|
||||||
|
|
||||||
starts = event.get(self.date_start)
|
|
||||||
ends = event.get(self.date_delay) or 1.0
|
|
||||||
span = 0
|
|
||||||
|
|
||||||
if starts and ends:
|
|
||||||
|
|
||||||
n = 0
|
|
||||||
h = ends
|
|
||||||
|
|
||||||
if ends == self.day_length:
|
|
||||||
span = 1
|
|
||||||
|
|
||||||
elif ends > self.day_length:
|
|
||||||
n = ends / self.day_length
|
|
||||||
h = ends % self.day_length
|
|
||||||
|
|
||||||
n = int(math.floor(n))
|
|
||||||
|
|
||||||
if h > 0:
|
|
||||||
span = n + 1
|
|
||||||
else:
|
|
||||||
span = n
|
|
||||||
ends = time.localtime(time.mktime(starts) + (h * 60 * 60) + (n * 24 * 60 * 60))
|
|
||||||
|
|
||||||
if starts and self.date_stop:
|
|
||||||
|
|
||||||
ends = event.get(self.date_stop)
|
|
||||||
if not ends:
|
|
||||||
ends = time.localtime(time.mktime(starts) + 60 * 60)
|
|
||||||
|
|
||||||
tds = time.mktime(starts)
|
|
||||||
tde = time.mktime(ends)
|
|
||||||
|
|
||||||
if tds >= tde:
|
|
||||||
tde = tds + 60 * 60
|
|
||||||
ends = time.localtime(tde)
|
|
||||||
|
|
||||||
n = (tde - tds) / (60 * 60)
|
|
||||||
|
|
||||||
if n >= self.day_length:
|
|
||||||
span = math.ceil(n / 24)
|
|
||||||
|
|
||||||
starts = self.format_datetime(starts, "datetime", True)
|
|
||||||
ends = self.format_datetime(ends, "datetime", True)
|
|
||||||
title = title.strip()
|
|
||||||
description = ', '.join(description).strip()
|
|
||||||
return {'id': event['id'], 'start_date': str(DT.datetime(*starts[:6])), 'end_date': str(DT.datetime(*ends[:6])), 'text': title, 'title': description, 'color': self.colors[event[self.color_field]][-1]}
|
|
||||||
|
|
|
@ -7,38 +7,27 @@ QWeb.add_template('/base_calendar/static/src/xml/base_calendar.xml');
|
||||||
openerp.base.views.add('calendar', 'openerp.base_calendar.CalendarView');
|
openerp.base.views.add('calendar', 'openerp.base_calendar.CalendarView');
|
||||||
openerp.base_calendar.CalendarView = openerp.base.View.extend({
|
openerp.base_calendar.CalendarView = openerp.base.View.extend({
|
||||||
// Dhtmlx scheduler ?
|
// Dhtmlx scheduler ?
|
||||||
init: function(parent, element_id, dataset, view_id) {
|
init: function(parent, element_id, dataset, view_id, options) {
|
||||||
this._super(parent, element_id);
|
this._super(parent, element_id);
|
||||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
this.set_default_options();
|
||||||
this.dataset = dataset;
|
this.dataset = dataset;
|
||||||
this.dataset_index = 0;
|
|
||||||
this.model = dataset.model;
|
this.model = dataset.model;
|
||||||
this.view_id = view_id;
|
this.view_id = view_id;
|
||||||
this.fields_view = {};
|
this.domain = this.dataset.domain || [];
|
||||||
this.widgets = {};
|
this.context = this.dataset.context || {};
|
||||||
this.widgets_counter = 0;
|
this.has_been_loaded = $.Deferred();
|
||||||
this.fields = this.dataset.fields ? this.dataset.fields: {};
|
this.options = options || {};
|
||||||
this.datarecord = {};
|
|
||||||
this.name = "";
|
|
||||||
this.date_start = "";
|
|
||||||
this.date_delay = "";
|
|
||||||
this.date_stop = "";
|
|
||||||
this.color_field = "";
|
|
||||||
this.day_lenth = 8;
|
|
||||||
this.colors = [];
|
|
||||||
this.color_values = [];
|
|
||||||
this.calendar_fields = {};
|
|
||||||
this.info_fields = [];
|
|
||||||
this.domain = this.dataset._domain ? this.dataset._domain: [];
|
|
||||||
this.context = {};
|
|
||||||
},
|
},
|
||||||
start: function() {
|
start: function() {
|
||||||
this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
|
this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id, 'toolbar': true}, this.on_loaded);
|
||||||
},
|
},
|
||||||
on_loaded: function(result) {
|
on_loaded: function(data) {
|
||||||
var self = this;
|
this.calendar_fields = {};
|
||||||
var params = {};
|
this.ids = this.dataset.ids;
|
||||||
this.fields_view = result.fields_view;
|
this.color_values = [];
|
||||||
|
this.info_fields = [];
|
||||||
|
|
||||||
|
this.fields_view = data.fields_view;
|
||||||
this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
|
this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
|
||||||
this.view_id = this.fields_view.view_id;
|
this.view_id = this.fields_view.view_id;
|
||||||
|
|
||||||
|
@ -54,171 +43,345 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
|
||||||
//* Calendar Fields *
|
//* Calendar Fields *
|
||||||
this.calendar_fields['date_start'] = {'name': this.date_start, 'kind': this.fields[this.date_start]['type']};
|
this.calendar_fields['date_start'] = {'name': this.date_start, 'kind': this.fields[this.date_start]['type']};
|
||||||
|
|
||||||
if(this.date_delay)
|
if (this.date_delay) {
|
||||||
this.calendar_fields['date_delay'] = {'name': this.date_delay, 'kind': this.fields[this.date_delay]['type']};
|
this.calendar_fields['date_delay'] = {'name': this.date_delay, 'kind': this.fields[this.date_delay]['type']};
|
||||||
|
}
|
||||||
|
|
||||||
if(this.date_stop)
|
if (this.date_stop) {
|
||||||
this.calendar_fields['date_stop'] = {'name': this.date_stop, 'kind': this.fields[this.date_stop]['type']};
|
this.calendar_fields['date_stop'] = {'name': this.date_stop, 'kind': this.fields[this.date_stop]['type']};
|
||||||
|
}
|
||||||
|
|
||||||
this.calendar_fields['day_length'] = this.day_length;
|
for (var fld = 0; fld < this.fields_view.arch.children.length; fld++) {
|
||||||
//* ------- *
|
|
||||||
|
|
||||||
for(var fld=0;fld<this.fields_view.arch.children.length;fld++) {
|
|
||||||
this.info_fields.push(this.fields_view.arch.children[fld].attrs.name);
|
this.info_fields.push(this.fields_view.arch.children[fld].attrs.name);
|
||||||
}
|
}
|
||||||
|
this.$element.html(QWeb.render("CalendarView", {"fields_view": this.fields_view}));
|
||||||
|
|
||||||
|
if (this.options.sidebar && this.options.sidebar_id) {
|
||||||
|
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
||||||
|
this.sidebar.start();
|
||||||
|
this.sidebar.navigator = new openerp.base_calendar.SidebarNavigator(this.sidebar, this.sidebar.add_section('navigator', "Navigator"), this);
|
||||||
|
this.sidebar.responsible = new openerp.base_calendar.SidebarResponsible(this.sidebar, this.sidebar.add_section('responsible', "Responsible"), this);
|
||||||
|
this.sidebar.add_toolbar(data.fields_view.toolbar);
|
||||||
|
this.set_common_sidebar_sections(this.sidebar);
|
||||||
|
this.sidebar.do_unfold();
|
||||||
|
this.sidebar.do_fold.add_last(this.resize_scheduler);
|
||||||
|
this.sidebar.do_unfold.add_last(this.resize_scheduler);
|
||||||
|
this.sidebar.do_toggle.add_last(this.resize_scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.init_scheduler();
|
||||||
this.load_scheduler();
|
this.load_scheduler();
|
||||||
|
this.has_been_loaded.resolve();
|
||||||
},
|
},
|
||||||
|
init_scheduler: function() {
|
||||||
load_scheduler:function() {
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
scheduler.config.api_date = "%Y-%m-%d %H:%M:%S";
|
||||||
|
scheduler.config.details_on_dblclick = true;
|
||||||
|
scheduler.config.details_on_create = true;
|
||||||
|
|
||||||
var params = {};
|
if (this.fields[this.date_start]['type'] == 'time') {
|
||||||
|
scheduler.config.xml_date = "%H:%M:%S";
|
||||||
|
} else {
|
||||||
|
scheduler.config.xml_date = "%Y-%m-%d %H:%M:%S";
|
||||||
|
}
|
||||||
|
|
||||||
params['model'] = this.model;
|
this.mode = this.mode || 'month';
|
||||||
params['calendar_fields'] = this.calendar_fields;
|
|
||||||
params['info_fields'] = this.info_fields;
|
|
||||||
params['fields'] = this.fields;
|
|
||||||
params['color_field'] = this.color_field;
|
|
||||||
params['domain'] = this.domain;
|
|
||||||
params['colors'] = this.colors;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start dhtmlx Schedular
|
|
||||||
*/
|
|
||||||
scheduler.clearAll();
|
|
||||||
scheduler.config.xml_date="%Y-%m-%d %H:%i";
|
|
||||||
scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views
|
scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views
|
||||||
|
|
||||||
this.rpc(
|
|
||||||
'/base_calendar/calendarview/schedule_events',
|
|
||||||
params,
|
|
||||||
function(result) {
|
|
||||||
self.schedule_events(result);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
schedule_events: function(result) {
|
|
||||||
var self = this;
|
|
||||||
var res = result.result;
|
|
||||||
var sidebar = result.sidebar;
|
|
||||||
this.$element.html(QWeb.render("CalendarView", {"view": this, "fields_view": this.fields_view, "sidebar":sidebar, "calendar":this}));
|
|
||||||
|
|
||||||
// Initialize Sceduler
|
// Initialize Sceduler
|
||||||
scheduler.init('openerp_scheduler',null,"month");
|
scheduler.init('openerp_scheduler', null, this.mode);
|
||||||
scheduler.parse(res,"json");
|
|
||||||
jQuery('#dhx_minical_icon').bind('click', this.mini_calendar);
|
|
||||||
|
|
||||||
|
// Event Options Click,edit
|
||||||
|
scheduler.attachEvent('onDblClick', this.popup_event);
|
||||||
|
|
||||||
// To Change Event
|
scheduler.attachEvent('onEventCreated', function(event_id, e) {
|
||||||
scheduler.attachEvent(
|
//Replace default Lightbox with Popup Form of new Event
|
||||||
'onEventChanged'
|
scheduler.showLightbox = function() {
|
||||||
,function(event_id, event_object) {
|
//Delete Newly created Event,Later we reload Scheduler
|
||||||
self.edit_event(event_id, event_object)
|
scheduler.deleteEvent(event_id);
|
||||||
|
self.popup_event();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
scheduler.attachEvent('onBeforeEventChanged', function(event_obj, native_event, is_new) {
|
||||||
* Create Sidebar
|
var is_event_exist = $.inArray(event_obj.id, self.dataset.ids);
|
||||||
*/
|
if (is_event_exist >= 0 || !is_new) {
|
||||||
jQuery('#calendar-sidebar').append(
|
// try to save Event.
|
||||||
jQuery('<table>',{'width':'100%','cellspacing': 0, 'cellpadding': 0, 'id':'cal-sidebar-option'})
|
var data = {};
|
||||||
)
|
self.mode = scheduler._mode;
|
||||||
for(s in sidebar) {
|
var date_format = self.calendar_fields.date_start.kind == 'time' ? 'HH:mm:ss' : 'yyyy-MM-dd HH:mm:ss';
|
||||||
jQuery('#cal-sidebar-option').append(
|
data[self.date_start] = event_obj.start_date.toString(date_format);
|
||||||
jQuery('<tr>').append(
|
|
||||||
jQuery('<td>').append(
|
if (self.date_stop) {
|
||||||
jQuery('<div>')
|
data[self.date_stop] = event_obj.end_date.toString(date_format);
|
||||||
.append(
|
|
||||||
jQuery('<input>',
|
|
||||||
{
|
|
||||||
'type': 'checkbox',
|
|
||||||
'id':sidebar[s][0],
|
|
||||||
'value':sidebar[s][0]
|
|
||||||
}).bind('click',function(){
|
|
||||||
self.reload_scheduler()
|
|
||||||
}),
|
|
||||||
sidebar[s][1]
|
|
||||||
)
|
|
||||||
.css('background-color',sidebar[s][sidebar[s].length-1])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
convert_date_format: function(start_date, end_date) {
|
if (self.date_delay) {
|
||||||
var params = {};
|
var tds = (event_obj.start_date.getOrdinalNumber() / 1e3 >> 0) - (event_obj.start_date.getOrdinalNumber() < 0);
|
||||||
params['start_date'] = start_date.getFullYear() +'-' + start_date.getMonth()+'-' + start_date.getDate()+' '+start_date.getHours()+':'+start_date.getMinutes()+':'+start_date.getSeconds();
|
var tde = (event_obj.end_date.getOrdinalNumber() / 1e3 >> 0) - (event_obj.end_date.getOrdinalNumber() < 0);
|
||||||
if(end_date) {
|
var n = (tde - tds) / (60 * 60);
|
||||||
params['end_date'] = end_date.getFullYear() +'-' + end_date.getMonth()+'-' + end_date.getDate()+' '+end_date.getHours()+':'+end_date.getMinutes()+':'+end_date.getSeconds();
|
if (n > self.day_length) {
|
||||||
|
var d = Math.floor(n / 24),
|
||||||
|
h = n % 24;
|
||||||
|
n = d * self.day_length + h;
|
||||||
}
|
}
|
||||||
return params;
|
data[self.date_delay] = n;
|
||||||
},
|
|
||||||
|
|
||||||
edit_event: function(evt_id, evt_object) {
|
|
||||||
var dates = this.convert_date_format(evt_object.start_date, evt_object.end_date);
|
|
||||||
this.rpc(
|
|
||||||
'/base_calendar/calendarview/edit_events',
|
|
||||||
{
|
|
||||||
'start_date': dates.start_date,
|
|
||||||
'end_date': dates.end_date,
|
|
||||||
'id': evt_id,
|
|
||||||
'model': this.model,
|
|
||||||
'info_fields': this.info_fields,
|
|
||||||
'fields': this.fields,
|
|
||||||
'calendar_fields': this.calendar_fields
|
|
||||||
}
|
}
|
||||||
);
|
self.dataset.write(event_obj.id, data, self.load_scheduler);
|
||||||
},
|
|
||||||
|
|
||||||
mini_calendar: function() {
|
|
||||||
|
|
||||||
if(scheduler.isCalendarVisible()) {
|
|
||||||
scheduler.destroyCalendar();
|
|
||||||
} else {
|
} else {
|
||||||
scheduler.renderCalendar({
|
// new Event.
|
||||||
position:"dhx_minical_icon",
|
return true;
|
||||||
date:scheduler._date,
|
|
||||||
navigation:true,
|
|
||||||
handler:function(date,calendar){
|
|
||||||
scheduler.setCurrentView(date);
|
|
||||||
scheduler.destroyCalendar()
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
scheduler.renderCalendar({
|
||||||
|
container: this.sidebar.navigator.element_id,
|
||||||
|
navigation: true,
|
||||||
|
date: scheduler._date,
|
||||||
|
handler: function(date, calendar) {
|
||||||
|
scheduler.setCurrentView(date, 'day');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resize_scheduler: function() {
|
||||||
|
scheduler.setCurrentView(scheduler._date);
|
||||||
|
},
|
||||||
|
load_scheduler: function() {
|
||||||
|
var self = this;
|
||||||
|
this.dataset.read_slice([], 0, false, function(events) {
|
||||||
|
if (self.session.locale_code) {
|
||||||
|
// TODO: replace $LAB
|
||||||
|
$LAB.setOptions({AlwaysPreserveOrder: true}).script([
|
||||||
|
'/base_calendar/static/lib/dhtmlxScheduler/sources/locale_' + self.session.locale_code + '.js',
|
||||||
|
'/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_' + self.session.locale_code + '.js'
|
||||||
|
]).wait(function() {
|
||||||
|
self.schedule_events(events);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.schedule_events(events);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
schedule_events: function(events) {
|
||||||
|
var self = this;
|
||||||
|
scheduler.clearAll();
|
||||||
|
|
||||||
|
//To parse Events we have to convert date Format
|
||||||
|
var res_events = [],
|
||||||
|
sidebar_items = [],
|
||||||
|
sidebar_ids = [];
|
||||||
|
for (var e = 0; e < events.length; e++) {
|
||||||
|
var evt = events[e];
|
||||||
|
if (!evt[this.date_start]) {
|
||||||
|
this.notification.warn("Start date is not defined for event :", evt['id']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fields[this.date_start]['type'] == 'date') {
|
||||||
|
evt[this.date_start] = openerp.base.parse_date(evt[this.date_start]).set({hour: 9}).toString('yyyy-MM-dd HH:mm:ss');
|
||||||
|
}
|
||||||
|
if (this.date_stop && evt[this.date_stop] && this.fields[this.date_stop]['type'] == 'date') {
|
||||||
|
evt[this.date_stop] = openerp.base.parse_date(evt[this.date_stop]).set({hour: 17}).toString('yyyy-MM-dd HH:mm:ss');
|
||||||
|
}
|
||||||
|
if (this.color_field) {
|
||||||
|
var user = evt[this.color_field];
|
||||||
|
if (user) {
|
||||||
|
if (_.indexOf(sidebar_ids, user[0]) === -1) {
|
||||||
|
sidebar_items.push({
|
||||||
|
id: user[0],
|
||||||
|
name: user[1],
|
||||||
|
// TODO: use color table
|
||||||
|
color: '#dddddd'
|
||||||
|
});
|
||||||
|
sidebar_ids.push(user[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res_events.push(this.convert_event(evt));
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduler.parse(res_events, 'json');
|
||||||
|
this.resize_scheduler();
|
||||||
|
this.sidebar.responsible.on_events_loaded(sidebar_items);
|
||||||
|
},
|
||||||
|
convert_event: function(event) {
|
||||||
|
var starts = event[this.date_start],
|
||||||
|
ends = event[this.date_delay] || 1,
|
||||||
|
span = 0,
|
||||||
|
res_text = '',
|
||||||
|
res_description = [];
|
||||||
|
|
||||||
|
var parse_start_date = openerp.base.parse_datetime(starts);
|
||||||
|
if (event[this.date_stop]) {
|
||||||
|
var parse_end_date = openerp.base.parse_datetime(event[this.date_stop]);
|
||||||
|
}
|
||||||
|
if (this.info_fields) {
|
||||||
|
var fld = event[this.info_fields[0]];
|
||||||
|
|
||||||
|
if (typeof fld == 'object') {
|
||||||
|
res_text = fld[fld.length -1];
|
||||||
|
} else {
|
||||||
|
res_text = fld;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sliced_info_fields = this.info_fields.slice(1);
|
||||||
|
for (sl_fld in sliced_info_fields) {
|
||||||
|
var slc_fld = event[sliced_info_fields[sl_fld]];
|
||||||
|
|
||||||
|
if (typeof slc_fld == 'object') {
|
||||||
|
res_description.push(slc_fld[slc_fld.length - 1]);
|
||||||
|
} else {
|
||||||
|
if(slc_fld) res_description.push(slc_fld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (starts && ends) {
|
||||||
|
var n = 0,
|
||||||
|
h = ends;
|
||||||
|
if (ends == this.day_length) {
|
||||||
|
span = 1;
|
||||||
|
} else if (ends > this.day_length) {
|
||||||
|
n = ends / this.day_length;
|
||||||
|
h = ends % this.day_length;
|
||||||
|
n = parseInt(Math.floor(n));
|
||||||
|
|
||||||
|
if (h > 0) {
|
||||||
|
span = n + 1;
|
||||||
|
} else {
|
||||||
|
span = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var start = parse_start_date.setTime((parse_start_date.getTime() + (h * 60 * 60) + (n * 24 * 60 * 60)));
|
||||||
|
ends = parse_start_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (starts && this.date_stop) {
|
||||||
|
ends = parse_end_date;
|
||||||
|
if (event[this.date_stop] == undefined) {
|
||||||
|
var start = parse_start_date.setTime((parse_start_date.getTime() + (h * 60 * 60) + (n * 24 * 60 * 60)));
|
||||||
|
ends = parse_start_date;
|
||||||
|
}
|
||||||
|
var tds = parse_start_date.getTime(),
|
||||||
|
tde = parse_end_date.getTime();
|
||||||
|
|
||||||
|
if (tds >= tde) {
|
||||||
|
tde = tds + 60 * 60;
|
||||||
|
parse_end_date.setTime(tde);
|
||||||
|
ends = parse_end_date;
|
||||||
|
}
|
||||||
|
n = (tde - tds) / (60 * 60);
|
||||||
|
if (n >= this.day_length) {
|
||||||
|
span = Math.ceil(n / 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'start_date': parse_start_date.toString('yyyy-MM-dd HH:mm:ss'),
|
||||||
|
'end_date': ends.toString('yyyy-MM-dd HH:mm:ss'),
|
||||||
|
'text': res_text,
|
||||||
|
'id': event['id'],
|
||||||
|
'title': res_description.join()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
do_search: function(domains, contexts, groupbys) {
|
||||||
reload_scheduler: function() {
|
var self = this;
|
||||||
// self.color_field
|
this.rpc('/base/session/eval_domain_and_context', {
|
||||||
console.log('Reload Scheduler>>>')
|
domains: domains,
|
||||||
},
|
contexts: contexts,
|
||||||
do_search: function (domains, contexts, groupbys) {
|
group_by_seq: groupbys
|
||||||
this.notification.notify("Searching caldendar");
|
}, function (results) {
|
||||||
|
// TODO: handle non-empty results.group_by with read_group
|
||||||
|
self.dataset.context = self.context = results.context;
|
||||||
|
self.dataset.domain = self.domain = results.domain;
|
||||||
|
self.dataset.read_slice(_.keys(self.fields), 0, self.limit, function(events) {
|
||||||
|
self.schedule_events(events);
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
do_show: function () {
|
do_show: function () {
|
||||||
this.$element.show();
|
var self = this;
|
||||||
|
$.when(this.has_been_loaded).then(function() {
|
||||||
|
self.$element.show();
|
||||||
|
if (self.sidebar) {
|
||||||
|
self.sidebar.$element.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
do_hide: function () {
|
do_hide: function () {
|
||||||
this.$element.hide();
|
this.$element.hide();
|
||||||
|
if (this.sidebar) {
|
||||||
|
this.sidebar.$element.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
popup_event: function(event_id) {
|
||||||
|
var self = this;
|
||||||
|
if (event_id) event_id = parseInt(event_id, 10);
|
||||||
|
var action = {
|
||||||
|
res_model: this.dataset.model,
|
||||||
|
res_id: event_id,
|
||||||
|
views: [[false, 'form']],
|
||||||
|
type: 'ir.actions.act_window',
|
||||||
|
view_type: 'form',
|
||||||
|
view_mode: 'form',
|
||||||
|
flags : {
|
||||||
|
search_view: false,
|
||||||
|
sidebar : false,
|
||||||
|
views_switcher : false,
|
||||||
|
action_buttons : false,
|
||||||
|
pager: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var element_id = _.uniqueId("act_window_dialog");
|
||||||
|
var dialog = $('<div>', {
|
||||||
|
'id': element_id
|
||||||
|
}).dialog({
|
||||||
|
modal: true,
|
||||||
|
width: 'auto',
|
||||||
|
height: 'auto',
|
||||||
|
buttons: {
|
||||||
|
Cancel: function() {
|
||||||
|
$(this).dialog("destroy");
|
||||||
|
},
|
||||||
|
Save: function() {
|
||||||
|
var view_manager = action_manager.viewmanager;
|
||||||
|
var _dialog = this;
|
||||||
|
view_manager.views[view_manager.active_view].controller.do_save(function(r) {
|
||||||
|
$(_dialog).dialog("destroy");
|
||||||
|
// self.start();
|
||||||
|
self.load_scheduler();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var action_manager = new openerp.base.ActionManager(this, element_id);
|
||||||
|
action_manager.start();
|
||||||
|
action_manager.do_action(action);
|
||||||
|
//Default_get
|
||||||
|
if (!event_id) {
|
||||||
|
this.dataset.index = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//openerp.base.Action = openerp.base.Action.extend({
|
openerp.base_calendar.SidebarResponsible = openerp.base.Widget.extend({
|
||||||
// do_action_window: function(action) {
|
init: function(parent, element_id, view) {
|
||||||
// this._super.apply(this,arguments);
|
this._super(parent, element_id);
|
||||||
// for(var i = 0; i < action.views.length; i++) {
|
this.view = view;
|
||||||
// if(action.views[i][1] == "calendar") {
|
},
|
||||||
// this.calendar_id = action.views[i][0];
|
on_events_loaded: function(users) {
|
||||||
// break;
|
this.$element.html(QWeb.render('CalendarView.sidebar.responsible', { users : users }));
|
||||||
// }
|
// TODO: bind checkboxes reload sheduler
|
||||||
// }
|
}
|
||||||
// // IF there is a view calender
|
});
|
||||||
// // if(this.calendar_id
|
|
||||||
// },
|
openerp.base_calendar.SidebarNavigator = openerp.base.Widget.extend({
|
||||||
//});
|
init: function(parent, element_id, view) {
|
||||||
|
this._super(parent, element_id);
|
||||||
|
this.view = view;
|
||||||
|
},
|
||||||
|
on_events_loaded: function(events) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<t t-name="CalendarView">
|
<t t-name="CalendarView">
|
||||||
<h3 class="title"><t t-esc="view.fields_view.arch.attrs.string"/></h3>
|
<h3 class="title"><t t-esc="fields_view.arch.attrs.string"/></h3>
|
||||||
<table class="calendar-view" width="100%" height="100%" cellspacing="0" cellpadding="0">
|
<div id="openerp_scheduler" class="dhx_cal_container" style="height: 1000px;">
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div style="height: 1000px;width: 100%;">
|
|
||||||
<div id="calendar-sidebar">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td style="width:85%;" align="left">
|
|
||||||
<div id="openerp_scheduler" class="dhx_cal_container" style="height: 1000px;width: 100%;">
|
|
||||||
<div class="dhx_cal_navline">
|
<div class="dhx_cal_navline">
|
||||||
<div class="dhx_cal_prev_button"/>
|
<div class="dhx_cal_prev_button"/>
|
||||||
<div class="dhx_cal_next_button"/>
|
<div class="dhx_cal_next_button"/>
|
||||||
<div class="dhx_cal_today_button"/>
|
<div class="dhx_cal_today_button"/>
|
||||||
<div class="dhx_cal_date"/>
|
<div class="dhx_cal_date"/>
|
||||||
<div class="dhx_minical_icon" id="dhx_minical_icon"/>
|
|
||||||
<div class="dhx_cal_tab" name="day_tab" style="right:204px;"/>
|
<div class="dhx_cal_tab" name="day_tab" style="right:204px;"/>
|
||||||
<div class="dhx_cal_tab" name="week_tab" style="right:140px;"/>
|
<div class="dhx_cal_tab" name="week_tab" style="right:140px;"/>
|
||||||
<div class="dhx_cal_tab" name="month_tab" style="right:76px;"/>
|
<div class="dhx_cal_tab" name="month_tab" style="right:76px;"/>
|
||||||
|
@ -26,8 +16,11 @@
|
||||||
<div class="dhx_cal_data">
|
<div class="dhx_cal_data">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</t>
|
||||||
</tr>
|
<t t-name="CalendarView.sidebar.responsible">
|
||||||
</table>
|
<div t-foreach="users" t-as="user" class="oe_calendar_responsible" t-attf-style="background: #{user.color}">
|
||||||
</t>
|
<input type="checkbox" name="selection" t-att-value="user.id"/>
|
||||||
|
<span><t t-esc="user.name"/></span>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
openerp.base.diagram = function (openerp) {
|
openerp.base.diagram = function (openerp) {
|
||||||
|
|
||||||
openerp.base.views.add('diagram', 'openerp.base.DiagramView');
|
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){
|
init: function(view_manager, session, element_id, dataset, view_id){
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
this.view_manager = view_manager;
|
this.view_manager = view_manager;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
openerp.base_gantt = function (openerp) {
|
openerp.base_gantt = function (openerp) {
|
||||||
QWeb.add_template('/base_gantt/static/src/xml/base_gantt.xml');
|
QWeb.add_template('/base_gantt/static/src/xml/base_gantt.xml');
|
||||||
openerp.base.views.add('gantt', 'openerp.base_gantt.GanttView');
|
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) {
|
init: function(view_manager, session, element_id, dataset, view_id) {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
openerp.web_mobile.chrome_mobile = function(openerp) {
|
openerp.web_mobile.chrome_mobile = function(openerp) {
|
||||||
openerp.web_mobile.Shortcuts = openerp.base.Controller.extend({
|
openerp.web_mobile.Shortcuts = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id) {
|
init: function(session, element_id) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
},
|
},
|
||||||
|
@ -19,7 +19,7 @@ openerp.web_mobile.Shortcuts = openerp.base.Controller.extend({
|
||||||
this.listview.start();
|
this.listview.start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openerp.web_mobile.Header = openerp.base.Controller.extend({
|
openerp.web_mobile.Header = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id) {
|
init: function(session, element_id) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
},
|
},
|
||||||
|
@ -36,7 +36,7 @@ openerp.web_mobile.Header = openerp.base.Controller.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openerp.web_mobile.Secondary = openerp.base.Controller.extend({
|
openerp.web_mobile.Secondary = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id, secondary_menu_id) {
|
init: function(session, element_id, secondary_menu_id) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
this.data = secondary_menu_id;
|
this.data = secondary_menu_id;
|
||||||
|
@ -74,7 +74,7 @@ openerp.web_mobile.Secondary = openerp.base.Controller.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
openerp.web_mobile.Menu = openerp.base.Controller.extend({
|
openerp.web_mobile.Menu = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id, secondary_menu_id) {
|
init: function(session, element_id, secondary_menu_id) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
this.secondary_menu_id = secondary_menu_id;
|
this.secondary_menu_id = secondary_menu_id;
|
||||||
|
@ -106,7 +106,7 @@ openerp.web_mobile.Menu = openerp.base.Controller.extend({
|
||||||
this.secondary.start();
|
this.secondary.start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openerp.web_mobile.Options = openerp.base.Controller.extend({
|
openerp.web_mobile.Options = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id) {
|
init: function(session, element_id) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
},
|
},
|
||||||
|
@ -121,7 +121,7 @@ openerp.web_mobile.Options = openerp.base.Controller.extend({
|
||||||
this.login.start();
|
this.login.start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openerp.web_mobile.Login = openerp.base.Controller.extend({
|
openerp.web_mobile.Login = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id) {
|
init: function(session, element_id) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
},
|
},
|
||||||
|
@ -129,7 +129,7 @@ openerp.web_mobile.Login = openerp.base.Controller.extend({
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
jQuery("#oe_header").children().remove();
|
jQuery("#oe_header").children().remove();
|
||||||
this.rpc("/base/session/get_databases_list", {}, function(result) {
|
this.rpc("/base/database/get_list", {}, function(result) {
|
||||||
self.db_list = result.db_list;
|
self.db_list = result.db_list;
|
||||||
self.$element.html(QWeb.render("Login", self));
|
self.$element.html(QWeb.render("Login", self));
|
||||||
self.$element.find('#database').click(self.on_db_select);
|
self.$element.find('#database').click(self.on_db_select);
|
||||||
|
@ -190,7 +190,7 @@ openerp.web_mobile.Login = openerp.base.Controller.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openerp.web_mobile.MobileWebClient = openerp.base.Controller.extend({
|
openerp.web_mobile.MobileWebClient = openerp.base.Widget.extend({
|
||||||
init: function(element_id) {
|
init: function(element_id) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this._super(null, element_id);
|
this._super(null, element_id);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
openerp.web_mobile.form_mobile = function (openerp) {
|
openerp.web_mobile.form_mobile = function (openerp) {
|
||||||
openerp.web_mobile.FormView = openerp.base.Controller.extend({
|
openerp.web_mobile.FormView = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id, list_id, action) {
|
init: function(session, element_id, list_id, action) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
this.list_id = list_id;
|
this.list_id = list_id;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
openerp.web_mobile.list_mobile = function (openerp) {
|
openerp.web_mobile.list_mobile = function (openerp) {
|
||||||
openerp.web_mobile.ListView = openerp.base.Controller.extend({
|
openerp.web_mobile.ListView = openerp.base.Widget.extend({
|
||||||
init: function(session, element_id, list_id) {
|
init: function(session, element_id, list_id) {
|
||||||
this._super(session, element_id);
|
this._super(session, element_id);
|
||||||
this.list_id = list_id;
|
this.list_id = list_id;
|
||||||
|
|
|
@ -374,7 +374,10 @@ class HttpRequest(object):
|
||||||
akw = dict([(key, kw[key] if isinstance(kw[key], basestring) else type(kw[key])) for key in kw.keys()])
|
akw = dict([(key, kw[key] if isinstance(kw[key], basestring) else type(kw[key])) for key in kw.keys()])
|
||||||
print "POST --> %s.%s %s %r" % (controller.__class__.__name__, f.__name__, request, akw)
|
print "POST --> %s.%s %s %r" % (controller.__class__.__name__, f.__name__, request, akw)
|
||||||
r = f(controller, self, **kw)
|
r = f(controller, self, **kw)
|
||||||
print "<--", r
|
if isinstance(r, str):
|
||||||
|
print "<--", len(r), 'bytes'
|
||||||
|
else:
|
||||||
|
print "<--", len(r), 'characters'
|
||||||
print
|
print
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue