13
.bzrignore
|
@ -1,12 +1,11 @@
|
|||
RE:lib/(?!populate.sh).*
|
||||
.*
|
||||
*.egg-info
|
||||
*.orig
|
||||
bin/
|
||||
build/
|
||||
dist/
|
||||
include/
|
||||
RE:^bin/
|
||||
RE:^dist/
|
||||
RE:^include/
|
||||
|
||||
share/
|
||||
man/
|
||||
lib/
|
||||
RE:^share/
|
||||
RE:^man/
|
||||
RE:^lib/
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
'active': True,
|
||||
'js' : [
|
||||
"static/lib/datejs/date-en-US.js",
|
||||
"static/lib/jquery/jquery-1.5.2.js",
|
||||
"static/lib/jquery/jquery-1.6.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.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/superfish.js",
|
||||
"static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js",
|
||||
|
@ -19,7 +22,7 @@
|
|||
"static/lib/underscore/underscore.string.js",
|
||||
"static/src/js/boot.js",
|
||||
"static/src/js/core.js",
|
||||
"static/src/js/dates.js",
|
||||
"static/src/js/formats.js",
|
||||
"static/src/js/chrome.js",
|
||||
"static/src/js/views.js",
|
||||
"static/src/js/data.js",
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import base64, glob, os, re
|
||||
|
||||
import base64
|
||||
import csv
|
||||
import glob
|
||||
import operator
|
||||
import os
|
||||
import re
|
||||
import simplejson
|
||||
import textwrap
|
||||
import xmlrpclib
|
||||
from xml.etree import ElementTree
|
||||
from cStringIO import StringIO
|
||||
|
||||
import simplejson
|
||||
import cherrypy
|
||||
|
||||
import openerpweb
|
||||
import openerpweb.ast
|
||||
import openerpweb.nonliterals
|
||||
|
||||
import cherrypy
|
||||
import csv
|
||||
import xml.dom.minidom
|
||||
|
||||
# Should move to openerpweb.Xml2Json
|
||||
class Xml2Json:
|
||||
|
@ -84,6 +90,27 @@ def concat_files(file_list):
|
|||
files_concat = "".join(files_content)
|
||||
return files_concat
|
||||
|
||||
home_template = textwrap.dedent("""<!DOCTYPE html>
|
||||
<html style="height: 100%%">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP</title>
|
||||
%(javascript)s
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
QWeb = new QWeb2.Engine();
|
||||
openerp.init().base.webclient("oe");
|
||||
});
|
||||
</script>
|
||||
<link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
%(css)s
|
||||
<!--[if lte IE 7]>
|
||||
<link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body id="oe" class="openerp"></body>
|
||||
</html>
|
||||
""")
|
||||
class WebClient(openerpweb.Controller):
|
||||
_cp_path = "/base/webclient"
|
||||
|
||||
|
@ -112,57 +139,112 @@ class WebClient(openerpweb.Controller):
|
|||
return concat
|
||||
|
||||
@openerpweb.httprequest
|
||||
def home(self, req):
|
||||
template ="""<!DOCTYPE html>
|
||||
<html style="height: 100%%">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP</title>
|
||||
%s
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
QWeb = new QWeb2.Engine();
|
||||
openerp.init().base.webclient("oe");
|
||||
});
|
||||
</script>
|
||||
<link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
%s
|
||||
<!--[if lte IE 7]>
|
||||
<link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body id="oe" class="openerp"></body>
|
||||
</html>
|
||||
""".replace('\n'+' '*8,'\n')
|
||||
|
||||
def home(self, req, s_action=None):
|
||||
# script tags
|
||||
jslist = ['/base/webclient/js']
|
||||
if 1: # debug == 1
|
||||
jslist = manifest_glob(['base'], 'js')
|
||||
js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
|
||||
js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
|
||||
|
||||
# css tags
|
||||
csslist = ['/base/webclient/css']
|
||||
if 1: # debug == 1
|
||||
csslist = manifest_glob(['base'], 'css')
|
||||
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
|
||||
r = template % (js, css)
|
||||
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
|
||||
r = home_template % {
|
||||
'javascript': js,
|
||||
'css': css
|
||||
}
|
||||
return r
|
||||
|
||||
class Database(openerpweb.Controller):
|
||||
_cp_path = "/base/database"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get_databases_list(self, req):
|
||||
def get_list(self, req):
|
||||
proxy = req.session.proxy("db")
|
||||
dbs = proxy.list()
|
||||
h = req.httprequest.headers['Host'].split(':')[0]
|
||||
d = h.split('.')[0]
|
||||
r = cherrypy.config['openerp.dbfilter'].replace('%h',h).replace('%d',d)
|
||||
print "h,d",h,d,r
|
||||
dbs = [i for i in dbs if re.match(r,i)]
|
||||
r = cherrypy.config['openerp.dbfilter'].replace('%h', h).replace('%d', d)
|
||||
dbs = [i for i in dbs if re.match(r, i)]
|
||||
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 = (
|
||||
params['super_admin_pwd'],
|
||||
params['db_name'],
|
||||
bool(params.get('demo_data')),
|
||||
params['db_lang'],
|
||||
params['create_admin_pwd']
|
||||
)
|
||||
|
||||
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):
|
||||
_cp_path = "/base/session"
|
||||
|
||||
|
@ -180,6 +262,16 @@ class Session(openerpweb.Controller):
|
|||
return req.session.model('ir.ui.view_sc').get_sc(req.session._uid, "ir.ui.menu",
|
||||
req.session.eval_context(req.context))
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get_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
|
||||
def modules(self, req):
|
||||
# TODO query server for installed web modules
|
||||
|
@ -282,6 +374,11 @@ class Session(openerpweb.Controller):
|
|||
return None
|
||||
return saved_actions["actions"].get(key)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def check(self, req):
|
||||
req.session.assert_valid()
|
||||
return None
|
||||
|
||||
def eval_context_and_domain(session, context, domain=None):
|
||||
e_context = session.eval_context(context)
|
||||
# should we give the evaluated context as an evaluation context to the domain?
|
||||
|
@ -293,26 +390,25 @@ def load_actions_from_ir_values(req, key, key2, models, meta, context):
|
|||
Values = req.session.model('ir.values')
|
||||
actions = Values.get(key, key2, models, meta, context)
|
||||
|
||||
return [(id, name, clean_action(action, req.session))
|
||||
return [(id, name, clean_action(action, req.session, context=context))
|
||||
for id, name, action in actions]
|
||||
|
||||
def clean_action(action, session):
|
||||
def clean_action(action, session, context=None):
|
||||
action.setdefault('flags', {})
|
||||
if action['type'] != 'ir.actions.act_window':
|
||||
return action
|
||||
# values come from the server, we can just eval them
|
||||
if isinstance(action.get('context', None), basestring):
|
||||
if isinstance(action.get('context'), basestring):
|
||||
action['context'] = eval(
|
||||
action['context'],
|
||||
session.evaluation_context()) or {}
|
||||
session.evaluation_context(context=context)) or {}
|
||||
|
||||
if isinstance(action.get('domain', None), basestring):
|
||||
if isinstance(action.get('domain'), basestring):
|
||||
action['domain'] = eval(
|
||||
action['domain'],
|
||||
session.evaluation_context(
|
||||
action.get('context', {}))) or []
|
||||
if 'flags' not in action:
|
||||
# Set empty flags dictionary for web client.
|
||||
action['flags'] = dict()
|
||||
|
||||
return fix_view_modes(action)
|
||||
|
||||
def generate_views(action):
|
||||
|
@ -463,6 +559,7 @@ class DataSet(openerpweb.Controller):
|
|||
:rtype: list
|
||||
"""
|
||||
Model = request.session.model(model)
|
||||
|
||||
context, domain = eval_context_and_domain(
|
||||
request.session, request.context, domain)
|
||||
|
||||
|
@ -485,9 +582,14 @@ class DataSet(openerpweb.Controller):
|
|||
}
|
||||
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def read(self, request, model, ids, fields=False):
|
||||
return self.do_search_read(request, model, ids, fields)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get(self, request, model, ids, fields=False):
|
||||
return self.do_get(request, model, ids, fields)
|
||||
|
||||
def do_get(self, request, model, ids, fields=False):
|
||||
""" Fetches and returns the records of the model ``model`` whose ids
|
||||
are in ``ids``.
|
||||
|
@ -572,6 +674,12 @@ class DataSet(openerpweb.Controller):
|
|||
Model = req.session.model(model)
|
||||
return Model.default_get(fields, req.session.eval_context(req.context))
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def name_search(self, req, model, search_str, domain=[], context={}):
|
||||
m = req.session.model(model)
|
||||
r = m.name_search(search_str+'%', domain, '=ilike', context)
|
||||
return {'result': r}
|
||||
|
||||
class DataGroup(openerpweb.Controller):
|
||||
_cp_path = "/base/group"
|
||||
@openerpweb.jsonrequest
|
||||
|
@ -905,9 +1013,21 @@ class Action(openerpweb.Controller):
|
|||
return clean_action(req.session.model('ir.actions.server').run(
|
||||
[action_id], req.session.eval_context(req.context)), req.session)
|
||||
|
||||
class TreeView(View):
|
||||
_cp_path = "/base/treeview"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req, model, view_id, toolbar=False):
|
||||
return self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def action(self, req, model, id):
|
||||
return load_actions_from_ir_values(
|
||||
req,'action', 'tree_but_open',[(model, id)],
|
||||
False, req.session.eval_context(req.context))
|
||||
|
||||
def export_csv(fields, result):
|
||||
import StringIO
|
||||
fp = StringIO.StringIO()
|
||||
fp = StringIO()
|
||||
writer = csv.writer(fp, quoting=csv.QUOTE_ALL)
|
||||
|
||||
writer.writerow(fields)
|
||||
|
@ -931,7 +1051,6 @@ def export_csv(fields, result):
|
|||
return data
|
||||
|
||||
def export_xls(fieldnames, table):
|
||||
import StringIO
|
||||
try:
|
||||
import xlwt
|
||||
except ImportError:
|
||||
|
@ -953,7 +1072,7 @@ def export_xls(fieldnames, table):
|
|||
worksheet.write(row_index + 1, cell_index, cell_value, style)
|
||||
|
||||
|
||||
fp = StringIO.StringIO()
|
||||
fp = StringIO()
|
||||
workbook.save(fp)
|
||||
fp.seek(0)
|
||||
data = fp.read()
|
||||
|
@ -961,17 +1080,6 @@ def export_xls(fieldnames, table):
|
|||
#return data.decode('ISO-8859-1')
|
||||
return unicode(data, 'utf-8', 'replace')
|
||||
|
||||
def node_attributes(node):
|
||||
attrs = node.attributes
|
||||
|
||||
if not attrs:
|
||||
return {}
|
||||
# localName can be a unicode string, we're using attribute names as
|
||||
# **kwargs keys and python-level kwargs don't take unicode keys kindly
|
||||
# (they blow up) so we need to ensure all keys are ``str``
|
||||
return dict([(str(attrs.item(i).localName), attrs.item(i).nodeValue)
|
||||
for i in range(attrs.length)])
|
||||
|
||||
class Export(View):
|
||||
_cp_path = "/base/export"
|
||||
|
||||
|
@ -1130,4 +1238,3 @@ class Export(View):
|
|||
return export_xls(field, result)
|
||||
else:
|
||||
return export_csv(field, result)
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -1,5 +1,7 @@
|
|||
// TODO: trim support
|
||||
// TODO: line number -> https://bugzilla.mozilla.org/show_bug.cgi?id=618650
|
||||
// TODO: templates orverwritten could be called by t-call="__super__" ?
|
||||
// TODO: t-set + t-value + children node == scoped variable ?
|
||||
var QWeb2 = {
|
||||
expressions_cache: {},
|
||||
reserved_words: 'true,false,NaN,null,undefined,debugger,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','),
|
||||
|
@ -19,7 +21,12 @@ var QWeb2 = {
|
|||
if (context.template) {
|
||||
prefix += " - template['" + context.template + "']";
|
||||
}
|
||||
throw prefix + ": " + message;
|
||||
throw new Error(prefix + ": " + message);
|
||||
},
|
||||
warning : function(message) {
|
||||
if (typeof(window) !== 'undefined' && window.console) {
|
||||
window.console.warn(message);
|
||||
}
|
||||
},
|
||||
trim: function(s, mode) {
|
||||
switch (mode) {
|
||||
|
@ -638,6 +645,9 @@ QWeb2.Element = (function() {
|
|||
compile_action_set : function(value) {
|
||||
var variable = this.format_expression(value);
|
||||
if (this.actions['value']) {
|
||||
if (this.children.length) {
|
||||
this.engine.tools.warning("@set with @value plus node chidren found. Children are ignored.");
|
||||
}
|
||||
this.top(variable + " = (" + (this.format_expression(this.actions['value'])) + ");");
|
||||
this.process_children = false;
|
||||
} else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Underscore.js 1.1.5
|
||||
// Underscore.js 1.1.7
|
||||
// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Underscore is freely distributable under the MIT license.
|
||||
// Portions of Underscore are inspired or borrowed from Prototype,
|
||||
|
@ -55,25 +55,26 @@
|
|||
module.exports = _;
|
||||
_._ = _;
|
||||
} else {
|
||||
root._ = _;
|
||||
// Exported as a string, for Closure Compiler "advanced" mode.
|
||||
root['_'] = _;
|
||||
}
|
||||
|
||||
// Current version.
|
||||
_.VERSION = '1.1.5';
|
||||
_.VERSION = '1.1.7';
|
||||
|
||||
// Collection Functions
|
||||
// --------------------
|
||||
|
||||
// The cornerstone, an `each` implementation, aka `forEach`.
|
||||
// Handles objects implementing `forEach`, arrays, and raw objects.
|
||||
// Handles objects with the built-in `forEach`, arrays, and raw objects.
|
||||
// Delegates to **ECMAScript 5**'s native `forEach` if available.
|
||||
var each = _.each = _.forEach = function(obj, iterator, context) {
|
||||
if (obj == null) return;
|
||||
if (nativeForEach && obj.forEach === nativeForEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (_.isNumber(obj.length)) {
|
||||
} else if (obj.length === +obj.length) {
|
||||
for (var i = 0, l = obj.length; i < l; i++) {
|
||||
if (iterator.call(context, obj[i], i, obj) === breaker) return;
|
||||
if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
|
||||
}
|
||||
} else {
|
||||
for (var key in obj) {
|
||||
|
@ -106,7 +107,7 @@
|
|||
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
|
||||
}
|
||||
each(obj, function(value, index, list) {
|
||||
if (!initial && index === 0) {
|
||||
if (!initial) {
|
||||
memo = value;
|
||||
initial = true;
|
||||
} else {
|
||||
|
@ -168,7 +169,6 @@
|
|||
// Delegates to **ECMAScript 5**'s native `every` if available.
|
||||
// Aliased as `all`.
|
||||
_.every = _.all = function(obj, iterator, context) {
|
||||
iterator = iterator || _.identity;
|
||||
var result = true;
|
||||
if (obj == null) return result;
|
||||
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
||||
|
@ -187,9 +187,9 @@
|
|||
if (obj == null) return result;
|
||||
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
||||
each(obj, function(value, index, list) {
|
||||
if (result = iterator.call(context, value, index, list)) return breaker;
|
||||
if (result |= iterator.call(context, value, index, list)) return breaker;
|
||||
});
|
||||
return result;
|
||||
return !!result;
|
||||
};
|
||||
|
||||
// Determine if a given value is included in the array or object using `===`.
|
||||
|
@ -208,7 +208,7 @@
|
|||
_.invoke = function(obj, method) {
|
||||
var args = slice.call(arguments, 2);
|
||||
return _.map(obj, function(value) {
|
||||
return (method ? value[method] : value).apply(value, args);
|
||||
return (method.call ? method || value : value[method]).apply(value, args);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -252,10 +252,20 @@
|
|||
}), 'value');
|
||||
};
|
||||
|
||||
// Groups the object's values by a criterion produced by an iterator
|
||||
_.groupBy = function(obj, iterator) {
|
||||
var result = {};
|
||||
each(obj, function(value, index) {
|
||||
var key = iterator(value, index);
|
||||
(result[key] || (result[key] = [])).push(value);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// Use a comparator function to figure out at what index an object should
|
||||
// be inserted so as to maintain order. Uses binary search.
|
||||
_.sortedIndex = function(array, obj, iterator) {
|
||||
iterator = iterator || _.identity;
|
||||
iterator || (iterator = _.identity);
|
||||
var low = 0, high = array.length;
|
||||
while (low < high) {
|
||||
var mid = (low + high) >> 1;
|
||||
|
@ -268,7 +278,7 @@
|
|||
_.toArray = function(iterable) {
|
||||
if (!iterable) return [];
|
||||
if (iterable.toArray) return iterable.toArray();
|
||||
if (_.isArray(iterable)) return iterable;
|
||||
if (_.isArray(iterable)) return slice.call(iterable);
|
||||
if (_.isArguments(iterable)) return slice.call(iterable);
|
||||
return _.values(iterable);
|
||||
};
|
||||
|
@ -317,8 +327,7 @@
|
|||
|
||||
// Return a version of the array that does not contain the specified value(s).
|
||||
_.without = function(array) {
|
||||
var values = slice.call(arguments, 1);
|
||||
return _.filter(array, function(value){ return !_.include(values, value); });
|
||||
return _.difference(array, slice.call(arguments, 1));
|
||||
};
|
||||
|
||||
// Produce a duplicate-free version of the array. If the array has already
|
||||
|
@ -331,9 +340,15 @@
|
|||
}, []);
|
||||
};
|
||||
|
||||
// Produce an array that contains the union: each distinct element from all of
|
||||
// the passed-in arrays.
|
||||
_.union = function() {
|
||||
return _.uniq(_.flatten(arguments));
|
||||
};
|
||||
|
||||
// Produce an array that contains every item shared between all the
|
||||
// passed-in arrays.
|
||||
_.intersect = function(array) {
|
||||
// passed-in arrays. (Aliased as "intersect" for back-compat.)
|
||||
_.intersection = _.intersect = function(array) {
|
||||
var rest = slice.call(arguments, 1);
|
||||
return _.filter(_.uniq(array), function(item) {
|
||||
return _.every(rest, function(other) {
|
||||
|
@ -342,6 +357,12 @@
|
|||
});
|
||||
};
|
||||
|
||||
// Take the difference between one array and another.
|
||||
// Only the elements present in just the first array will remain.
|
||||
_.difference = function(array, other) {
|
||||
return _.filter(array, function(value){ return !_.include(other, value); });
|
||||
};
|
||||
|
||||
// Zip together multiple lists into a single array -- elements that share
|
||||
// an index go together.
|
||||
_.zip = function() {
|
||||
|
@ -408,8 +429,9 @@
|
|||
// Create a function bound to a given object (assigning `this`, and arguments,
|
||||
// optionally). Binding with arguments is also known as `curry`.
|
||||
// Delegates to **ECMAScript 5**'s native `Function.bind` if available.
|
||||
// We check for `func.bind` first, to fail fast when `func` is undefined.
|
||||
_.bind = function(func, obj) {
|
||||
if (nativeBind && func.bind === nativeBind) return func.bind.apply(func, slice.call(arguments, 1));
|
||||
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
||||
var args = slice.call(arguments, 2);
|
||||
return function() {
|
||||
return func.apply(obj, args.concat(slice.call(arguments)));
|
||||
|
@ -428,7 +450,7 @@
|
|||
// Memoize an expensive function by storing its results.
|
||||
_.memoize = function(func, hasher) {
|
||||
var memo = {};
|
||||
hasher = hasher || _.identity;
|
||||
hasher || (hasher = _.identity);
|
||||
return function() {
|
||||
var key = hasher.apply(this, arguments);
|
||||
return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
|
||||
|
@ -502,13 +524,21 @@
|
|||
var funcs = slice.call(arguments);
|
||||
return function() {
|
||||
var args = slice.call(arguments);
|
||||
for (var i=funcs.length-1; i >= 0; i--) {
|
||||
for (var i = funcs.length - 1; i >= 0; i--) {
|
||||
args = [funcs[i].apply(this, args)];
|
||||
}
|
||||
return args[0];
|
||||
};
|
||||
};
|
||||
|
||||
// Returns a function that will only be executed after being called N times.
|
||||
_.after = function(times, func) {
|
||||
return function() {
|
||||
if (--times < 1) { return func.apply(this, arguments); }
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Object Functions
|
||||
// ----------------
|
||||
|
||||
|
@ -529,13 +559,19 @@
|
|||
// Return a sorted list of the function names available on the object.
|
||||
// Aliased as `methods`
|
||||
_.functions = _.methods = function(obj) {
|
||||
return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
|
||||
var names = [];
|
||||
for (var key in obj) {
|
||||
if (_.isFunction(obj[key])) names.push(key);
|
||||
}
|
||||
return names.sort();
|
||||
};
|
||||
|
||||
// Extend a given object with all the properties in passed-in object(s).
|
||||
_.extend = function(obj) {
|
||||
each(slice.call(arguments, 1), function(source) {
|
||||
for (var prop in source) obj[prop] = source[prop];
|
||||
for (var prop in source) {
|
||||
if (source[prop] !== void 0) obj[prop] = source[prop];
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
|
@ -543,7 +579,9 @@
|
|||
// Fill in a given object with default properties.
|
||||
_.defaults = function(obj) {
|
||||
each(slice.call(arguments, 1), function(source) {
|
||||
for (var prop in source) if (obj[prop] == null) obj[prop] = source[prop];
|
||||
for (var prop in source) {
|
||||
if (obj[prop] == null) obj[prop] = source[prop];
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
|
@ -577,6 +615,7 @@
|
|||
if (b._chain) b = b._wrapped;
|
||||
// One of them implements an isEqual()?
|
||||
if (a.isEqual) return a.isEqual(b);
|
||||
if (b.isEqual) return b.isEqual(a);
|
||||
// Check dates' integer values.
|
||||
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
|
||||
// Both are NaN?
|
||||
|
@ -618,6 +657,11 @@
|
|||
return toString.call(obj) === '[object Array]';
|
||||
};
|
||||
|
||||
// Is a given variable an object?
|
||||
_.isObject = function(obj) {
|
||||
return obj === Object(obj);
|
||||
};
|
||||
|
||||
// Is a given variable an arguments object?
|
||||
_.isArguments = function(obj) {
|
||||
return !!(obj && hasOwnProperty.call(obj, 'callee'));
|
||||
|
|
|
@ -35,7 +35,8 @@ body.openerp {
|
|||
}
|
||||
|
||||
/* STATES */
|
||||
.openerp .on_logged {
|
||||
.openerp .on_logged,
|
||||
.openerp .db_options_row {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -138,10 +139,84 @@ body.openerp {
|
|||
}
|
||||
.openerp.login-mode .menu,
|
||||
.openerp.login-mode .secondary_menu,
|
||||
.openerp.login-mode .oe-application {
|
||||
.openerp.login-mode .oe-application,
|
||||
.openerp.login-mode .db_options_row {
|
||||
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 !important;
|
||||
}
|
||||
|
||||
.db_option_table input[type="text"], .db_option_table input[type="password"], .db_option_table 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*/
|
||||
.openerp .main_table {
|
||||
width: 100%;
|
||||
|
@ -161,14 +236,14 @@ body.openerp {
|
|||
|
||||
.openerp .menu {
|
||||
height: 34px;
|
||||
background: #cc4e45; /* Old browsers */
|
||||
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-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: -ms-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* IE10+ */
|
||||
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: #cc4e45; /* Old browsers */
|
||||
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-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: -ms-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#CC4E45', endColorstr='#7A211A',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */
|
||||
}
|
||||
.openerp .menu td {
|
||||
text-align: center;
|
||||
|
@ -181,20 +256,20 @@ background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */
|
|||
margin: 3px 2px;
|
||||
padding: 0 8px;
|
||||
|
||||
background: #bd5e54; /* Old browsers */
|
||||
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-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Chrome10+,Safari5.1+ */
|
||||
background: -o-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Opera11.10+ */
|
||||
background: -ms-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
|
||||
background: #bd5e54; /* Old browsers */
|
||||
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-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Chrome10+,Safari5.1+ */
|
||||
background: -o-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Opera11.10+ */
|
||||
background: -ms-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
|
||||
|
||||
border: 1px solid #6E2A24;
|
||||
border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
|
||||
|
||||
color: #eee;
|
||||
text-shadow: #222 0 1px 0;
|
||||
text-decoration: none;
|
||||
|
@ -208,16 +283,16 @@ background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
|
|||
.openerp .menu a:hover,
|
||||
.openerp .menu a:focus,
|
||||
.openerp .menu a.active {
|
||||
background: #c6c6c6; /* Old browsers */
|
||||
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-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: -ms-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C6C6C6', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* W3C */
|
||||
/* for ie */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
||||
background: #c6c6c6; /* Old browsers */
|
||||
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-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: -ms-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C6C6C6', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* W3C */
|
||||
/* for ie */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
|
||||
|
||||
color: #fff;
|
||||
}
|
||||
|
@ -239,19 +314,19 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', end
|
|||
}
|
||||
.openerp .secondary_menu h3 {
|
||||
padding: 0 0 2px;
|
||||
background: #949292; /* Old browsers */
|
||||
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-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: -ms-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* W3C */
|
||||
/* for ie9 */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */
|
||||
background: #949292; /* Old browsers */
|
||||
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-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: -ms-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* 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;
|
||||
-moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px;
|
||||
}
|
||||
.openerp .secondary_menu h4 {
|
||||
padding: 0 0 2px 10px;
|
||||
|
@ -277,17 +352,16 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', end
|
|||
.openerp .secondary_menu h4:hover,
|
||||
.openerp .secondary_menu h4:active,
|
||||
.openerp .secondary_menu h4.active {
|
||||
background: #ffffff; /* Old browsers */
|
||||
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-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: -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 */
|
||||
background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* W3C */
|
||||
background: #ffffff; /* Old browsers */
|
||||
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-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: -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 */
|
||||
background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* W3C */
|
||||
/* 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;
|
||||
text-shadow: #fff 0 1px 0;
|
||||
border: none !important;
|
||||
|
@ -317,7 +391,6 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
float: left;
|
||||
height: 63px;
|
||||
width: 200px;
|
||||
margin-right: 10px;
|
||||
border: 1px solid white;
|
||||
border-right-color: black;
|
||||
border-bottom-color: black;
|
||||
|
@ -433,6 +506,7 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
}
|
||||
|
||||
/* Main Application */
|
||||
.openerp .oe-main-content,
|
||||
.openerp .oe-application {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
|
@ -780,7 +854,7 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
}
|
||||
|
||||
/* Inputs */
|
||||
.openerp input[type="text"], .openerp input[type="password"], .openerp select, .openerp textarea {
|
||||
.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms textarea {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
|
@ -794,17 +868,17 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
min-width: 90px;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
.openerp textarea {
|
||||
.openerp .oe_forms textarea {
|
||||
resize:vertical;
|
||||
}
|
||||
.openerp input[type="text"], .openerp input[type="password"], .openerp select, .openerp .button {
|
||||
.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .button {
|
||||
height: 22px;
|
||||
}
|
||||
.openerp .button {
|
||||
.openerp .oe_forms .button {
|
||||
color: #4c4c4c;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.openerp .button span {
|
||||
.openerp .oe_forms .button span {
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
@ -849,11 +923,11 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
height: 15px;
|
||||
}
|
||||
.openerp td.required input, .openerp td.required select {
|
||||
background-color: #D2D2FF;
|
||||
background-color: #D2D2FF !important;
|
||||
}
|
||||
.openerp td.invalid input, .openerp td.invalid select, .openerp td.invalid textarea {
|
||||
background-color: #F66;
|
||||
border: 1px solid #D00;
|
||||
background-color: #F66 !important;
|
||||
border: 1px solid #D00 !important;
|
||||
}
|
||||
.openerp div.oe-progressbar span {
|
||||
position: absolute;
|
||||
|
@ -979,7 +1053,7 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
|||
padding-left: 10px;
|
||||
padding-right: 21px;
|
||||
height: 21px;
|
||||
|
||||
|
||||
background: #ffffff; /* Old browsers */
|
||||
background: -moz-linear-gradient(top, #ffffff 0%, #ebe9e9 100%); /* FF3.6+ */
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ebe9e9)); /* Chrome,Safari4+ */
|
||||
|
@ -988,7 +1062,7 @@ background: -o-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Opera11.10+ */
|
|||
background: -ms-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* IE10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#EBE9E9',GradientType=0 ); /* IE6-9 */
|
||||
background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
|
||||
|
||||
|
||||
border: 1px solid #D2CFCF;
|
||||
border-right-width: 0;
|
||||
border-left-width: 0;
|
||||
|
@ -1093,9 +1167,45 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
|
|||
.openerp .oe-m2o-disabled-cm {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.parent_top {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
.openerp .oe-dialog-warning p {
|
||||
padding-left: 1em;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.openerp .dhx_mini_calendar {
|
||||
-moz-box-shadow: none;
|
||||
-khtml-box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.openerp .oe-treeview-table {
|
||||
width: 100%;
|
||||
}
|
||||
.treeview-tr, .treeview-td {
|
||||
cursor: pointer;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
.treeview-tr span, .treeview-td span {
|
||||
display: block;
|
||||
}
|
||||
.treeview-tr:first-of-type {
|
||||
background: transparent url(/base/static/src/img/expand.gif) 0 50% no-repeat;
|
||||
}
|
||||
.oe-open .treeview-tr:first-of-type {
|
||||
background-image: url(/base/static/src/img/collapse.gif);
|
||||
}
|
||||
.treeview-tr:first-of-type span,
|
||||
.treeview-td:first-of-type span {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.treeview-header {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 2.0 KiB |
|
@ -1,10 +1,11 @@
|
|||
//---------------------------------------------------------
|
||||
// OpenERP Web Boostrap
|
||||
//---------------------------------------------------------
|
||||
/*---------------------------------------------------------
|
||||
* OpenERP Web Boostrap Code
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @name openerp
|
||||
* @namespace
|
||||
* @namespace openerp
|
||||
* @namespace window.openerp
|
||||
*/
|
||||
(function() {
|
||||
if (this.openerp)
|
||||
|
@ -13,13 +14,8 @@
|
|||
|
||||
/** @lends openerp */
|
||||
var openerp = this.openerp = {
|
||||
/**
|
||||
* Debug flag turns on logging
|
||||
*/
|
||||
// debug flag
|
||||
debug: true,
|
||||
// element_ids registry linked to all controllers on the page
|
||||
// TODO rename to elements, or keep gtk naming?
|
||||
screen: {},
|
||||
// Per session namespace
|
||||
// openerp.<module> will map to
|
||||
// openerp.sessions.sessionname.<module> using a closure
|
||||
|
@ -39,8 +35,6 @@
|
|||
// this unique id will be replaced by hostname_databasename by
|
||||
// openerp.base.Connection on the first connection
|
||||
_session_id: "session" + session_counter++,
|
||||
screen: openerp.screen,
|
||||
sessions: openerp.sessions,
|
||||
base: {},
|
||||
web_mobile: {}
|
||||
};
|
||||
|
@ -50,16 +44,17 @@
|
|||
}
|
||||
return new_instance;
|
||||
}
|
||||
// TODO add initrpc to init core only for RPC
|
||||
};
|
||||
})();
|
||||
|
||||
//---------------------------------------------------------
|
||||
// OpenERP base module split
|
||||
//---------------------------------------------------------
|
||||
/*---------------------------------------------------------
|
||||
* OpenERP Web base module split
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.base = function(instance) {
|
||||
openerp.base.core(instance);
|
||||
openerp.base.dates(instance);
|
||||
openerp.base.formats(instance);
|
||||
openerp.base.chrome(instance);
|
||||
openerp.base.data(instance);
|
||||
if (openerp.base.views) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*---------------------------------------------------------
|
||||
* OpenERP base library
|
||||
* OpenERP Web chrome
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.base.chrome = function(openerp) {
|
||||
|
||||
<<<<<<< TREE
|
||||
openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{
|
||||
/**
|
||||
* @constructs
|
||||
|
@ -272,6 +273,8 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi
|
|||
}
|
||||
});
|
||||
|
||||
=======
|
||||
>>>>>>> MERGE-SOURCE
|
||||
openerp.base.Notification = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
|
@ -297,10 +300,10 @@ openerp.base.Notification = openerp.base.Widget.extend({
|
|||
openerp.base.Dialog = openerp.base.OldWidget.extend({
|
||||
dialog_title: "",
|
||||
identifier_prefix: 'dialog',
|
||||
init: function (parent, options) {
|
||||
init: function (parent, dialog_options) {
|
||||
var self = this;
|
||||
this._super(parent);
|
||||
this.options = {
|
||||
this.dialog_options = {
|
||||
modal: true,
|
||||
width: 'auto',
|
||||
min_width: 0,
|
||||
|
@ -310,27 +313,25 @@ openerp.base.Dialog = openerp.base.OldWidget.extend({
|
|||
max_height: '100%',
|
||||
autoOpen: false,
|
||||
buttons: {},
|
||||
beforeClose: function () {
|
||||
self.on_close();
|
||||
}
|
||||
beforeClose: function () { self.on_close(); }
|
||||
};
|
||||
for (var f in this) {
|
||||
if (f.substr(0, 10) == 'on_button_') {
|
||||
this.options.buttons[f.substr(10)] = this[f];
|
||||
this.dialog_options.buttons[f.substr(10)] = this[f];
|
||||
}
|
||||
}
|
||||
if (options) {
|
||||
this.set_options(options);
|
||||
if (dialog_options) {
|
||||
this.set_options(dialog_options);
|
||||
}
|
||||
},
|
||||
set_options: function(options) {
|
||||
options = options || {};
|
||||
options.width = this.get_width(options.width || this.options.width);
|
||||
options.min_width = this.get_width(options.min_width || this.options.min_width);
|
||||
options.max_width = this.get_width(options.max_width || this.options.max_width);
|
||||
options.height = this.get_height(options.height || this.options.height);
|
||||
options.min_height = this.get_height(options.min_height || this.options.min_height);
|
||||
options.max_height = this.get_height(options.max_height || this.options.max_width);
|
||||
options.width = this.get_width(options.width || this.dialog_options.width);
|
||||
options.min_width = this.get_width(options.min_width || this.dialog_options.min_width);
|
||||
options.max_width = this.get_width(options.max_width || this.dialog_options.max_width);
|
||||
options.height = this.get_height(options.height || this.dialog_options.height);
|
||||
options.min_height = this.get_height(options.min_height || this.dialog_options.min_height);
|
||||
options.max_height = this.get_height(options.max_height || this.dialog_options.max_width);
|
||||
|
||||
if (options.width !== 'auto') {
|
||||
if (options.width > options.max_width) options.width = options.max_width;
|
||||
|
@ -343,7 +344,7 @@ openerp.base.Dialog = openerp.base.OldWidget.extend({
|
|||
if (!options.title && this.dialog_title) {
|
||||
options.title = this.dialog_title;
|
||||
}
|
||||
_.extend(this.options, options);
|
||||
_.extend(this.dialog_options, options);
|
||||
},
|
||||
get_width: function(val) {
|
||||
return this.get_size(val.toString(), $(window.top).width());
|
||||
|
@ -360,20 +361,18 @@ openerp.base.Dialog = openerp.base.OldWidget.extend({
|
|||
return parseInt(val, 10);
|
||||
}
|
||||
},
|
||||
start: function (auto_open) {
|
||||
this.$dialog = $('<div id="' + this.element_id + '"></div>').dialog(this.options);
|
||||
if (auto_open !== false) {
|
||||
this.open();
|
||||
}
|
||||
start: function () {
|
||||
this.$dialog = $('<div id="' + this.element_id + '"></div>').dialog(this.dialog_options);
|
||||
this._super();
|
||||
return this;
|
||||
},
|
||||
open: function(options) {
|
||||
open: function(dialog_options) {
|
||||
// TODO fme: bind window on resize
|
||||
if (this.template) {
|
||||
this.$element.html(this.render());
|
||||
}
|
||||
this.set_options(options);
|
||||
this.$dialog.dialog(this.options).dialog('open');
|
||||
this.set_options(dialog_options);
|
||||
this.$dialog.dialog(this.dialog_options).dialog('open');
|
||||
},
|
||||
close: function() {
|
||||
// Closes the dialog but leave it in a state where it could be opened again.
|
||||
|
@ -417,8 +416,8 @@ openerp.base.CrashManager = openerp.base.Dialog.extend({
|
|||
this.dialog_title = "OpenERP Error";
|
||||
this.template = 'DialogTraceback';
|
||||
this.open({
|
||||
width: '80%',
|
||||
height: '80%'
|
||||
width: 'auto',
|
||||
height: 'auto'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -444,15 +443,313 @@ openerp.base.Loading = openerp.base.Widget.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.Widget.extend({
|
||||
remember_creditentials: true,
|
||||
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
this.has_local_storage = typeof(localStorage) != 'undefined';
|
||||
this.selected_db = null;
|
||||
this.selected_login = null;
|
||||
|
||||
if (this.has_local_storage && this.remember_creditentials) {
|
||||
this.selected_db = localStorage.getItem('last_db_login_success');
|
||||
this.selected_login = localStorage.getItem('last_login_login_success');
|
||||
|
@ -465,7 +762,7 @@ openerp.base.Login = openerp.base.Widget.extend({
|
|||
},
|
||||
start: function() {
|
||||
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.display();
|
||||
}, function() {
|
||||
|
@ -473,7 +770,16 @@ openerp.base.Login = openerp.base.Widget.extend({
|
|||
});
|
||||
},
|
||||
display: function() {
|
||||
var self = 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);
|
||||
},
|
||||
on_login_invalid: function() {
|
||||
|
@ -484,13 +790,22 @@ openerp.base.Login = openerp.base.Widget.extend({
|
|||
},
|
||||
on_submit: function(ev) {
|
||||
ev.preventDefault();
|
||||
var self = this;
|
||||
var $e = this.$element;
|
||||
var db = $e.find("form [name=db]").val();
|
||||
var login = $e.find("form input[name=login]").val();
|
||||
var password = $e.find("form input[name=password]").val();
|
||||
//$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() {
|
||||
if(self.session.session_is_valid()) {
|
||||
if (self.has_local_storage) {
|
||||
|
@ -542,7 +857,7 @@ openerp.base.Menu = openerp.base.Widget.extend({
|
|||
init: function(parent, element_id, secondary_menu_id) {
|
||||
this._super(parent, element_id);
|
||||
this.secondary_menu_id = secondary_menu_id;
|
||||
this.$secondary_menu = $("#" + secondary_menu_id);
|
||||
this.$secondary_menu = $("#" + secondary_menu_id).hide();
|
||||
this.menu = false;
|
||||
},
|
||||
start: function() {
|
||||
|
@ -601,7 +916,7 @@ openerp.base.Menu = openerp.base.Widget.extend({
|
|||
this.on_menu_action_loaded);
|
||||
}
|
||||
|
||||
$('.active', this.$element.add(this.$secondary_menu)).removeClass('active');
|
||||
$('.active', this.$element.add(this.$secondary_menu.show())).removeClass('active');
|
||||
$parent.addClass('active');
|
||||
$menu.addClass('active');
|
||||
$menu.parent('h4').addClass('active');
|
||||
|
@ -625,12 +940,10 @@ openerp.base.Homepage = openerp.base.Widget.extend({
|
|||
openerp.base.Preferences = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.ImportExport = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.WebClient = openerp.base.Widget.extend({
|
||||
init: function(element_id) {
|
||||
this._super(null, element_id);
|
||||
openerp.webclient = this;
|
||||
|
||||
QWeb.add_template("/base/static/src/xml/base.xml");
|
||||
var params = {};
|
||||
|
@ -642,7 +955,7 @@ openerp.base.WebClient = openerp.base.Widget.extend({
|
|||
this.session = new openerp.base.Session(this,"oe_errors");
|
||||
this.loading = new openerp.base.Loading(this,"oe_loading");
|
||||
this.crashmanager = new openerp.base.CrashManager(this);
|
||||
this.crashmanager.start(false);
|
||||
this.crashmanager.start();
|
||||
|
||||
// Do you autorize this ? will be replaced by notify() in controller
|
||||
openerp.base.Widget.prototype.notification = new openerp.base.Notification(this, "oe_notification");
|
||||
|
@ -657,6 +970,7 @@ openerp.base.WebClient = openerp.base.Widget.extend({
|
|||
|
||||
this.menu = new openerp.base.Menu(this, "oe_menu", "oe_secondary_menu");
|
||||
this.menu.on_action.add(this.on_menu_action);
|
||||
|
||||
},
|
||||
start: function() {
|
||||
this.session.start();
|
||||
|
@ -666,19 +980,72 @@ openerp.base.WebClient = openerp.base.Widget.extend({
|
|||
this.notification.notify("OpenERP Client", "The openerp client has been initialized.");
|
||||
},
|
||||
on_logged: function() {
|
||||
this.action_manager = new openerp.base.ActionManager(this, "oe_app");
|
||||
this.action_manager.start();
|
||||
if(this.action_manager)
|
||||
this.action_manager.stop();
|
||||
this.action_manager = new openerp.base.ActionManager(this);
|
||||
this.action_manager.appendTo($("#oe_app"));
|
||||
|
||||
// if using saved actions, load the action and give it to action manager
|
||||
var parameters = jQuery.deparam(jQuery.param.querystring());
|
||||
if(parameters["s_action"] != undefined) {
|
||||
var key = parseInt(parameters["s_action"]);
|
||||
if (parameters["s_action"] != undefined) {
|
||||
var key = parseInt(parameters["s_action"], 10);
|
||||
var self = this;
|
||||
this.rpc("/base/session/get_session_action", {key:key}, function(action) {
|
||||
self.action_manager.do_action(action);
|
||||
});
|
||||
} else if (openerp._modules_loaded) { // TODO: find better option than this
|
||||
this.load_url_state()
|
||||
} else {
|
||||
this.session.on_modules_loaded.add({
|
||||
callback: $.proxy(this, 'load_url_state'),
|
||||
unique: true,
|
||||
position: 'last'
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Loads state from URL if any, or checks if there is a home action and
|
||||
* loads that, assuming we're at the index
|
||||
*/
|
||||
load_url_state: function () {
|
||||
var self = this;
|
||||
// TODO: add actual loading if there is url state to unpack, test on window.location.hash
|
||||
|
||||
// not logged in
|
||||
if (!this.session.uid) { return; }
|
||||
var ds = new openerp.base.DataSetSearch(this, 'res.users');
|
||||
ds.read_ids([this.session.uid], ['action_id'], function (users) {
|
||||
var home_action = users[0].action_id;
|
||||
if (!home_action) {
|
||||
self.default_home();
|
||||
return;
|
||||
}
|
||||
self.execute_home_action(home_action[0], ds);
|
||||
})
|
||||
},
|
||||
default_home: function () {
|
||||
},
|
||||
/**
|
||||
* Bundles the execution of the home action
|
||||
*
|
||||
* @param {Number} action action id
|
||||
* @param {openerp.base.DataSet} dataset action executor
|
||||
*/
|
||||
execute_home_action: function (action, dataset) {
|
||||
var self = this;
|
||||
this.rpc('/base/action/load', {
|
||||
action_id: action,
|
||||
context: dataset.get_context()
|
||||
}, function (meh) {
|
||||
var action = meh.result;
|
||||
action.context = _.extend(action.context || {}, {
|
||||
active_id: false,
|
||||
active_ids: [false],
|
||||
active_model: dataset.model
|
||||
});
|
||||
self.action_manager.do_action(action);
|
||||
});
|
||||
},
|
||||
on_menu_action: function(action) {
|
||||
this.action_manager.do_action(action);
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*---------------------------------------------------------
|
||||
* OpenERP controller framework
|
||||
* OpenERP Web core
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
openerp.base.core = function(openerp) {
|
||||
|
@ -7,70 +7,98 @@ openerp.base.core = function(openerp) {
|
|||
* John Resig Class with factory improvement
|
||||
*/
|
||||
(function() {
|
||||
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
// The base Class implementation (does nothing)
|
||||
this.Class = function(){};
|
||||
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
|
||||
Class.extend = function(prop) {
|
||||
var _super = this.prototype;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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];
|
||||
// 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;
|
||||
// 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];
|
||||
}
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
Class.include = function (properties) {
|
||||
for (var name in properties) {
|
||||
if (typeof properties[name] !== 'function'
|
||||
|| !fnTest.test(properties[name])) {
|
||||
prototype[name] = properties[name];
|
||||
} else if (typeof prototype[name] === 'function'
|
||||
&& prototype.hasOwnProperty(name)) {
|
||||
prototype[name] = (function (name, fn, previous) {
|
||||
return function () {
|
||||
var tmp = this._super;
|
||||
this._super = previous;
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
return ret;
|
||||
}
|
||||
})(name, properties[name], prototype[name]);
|
||||
} else if (typeof _super[name] === 'function') {
|
||||
prototype[name] = (function (name, fn) {
|
||||
return function () {
|
||||
var tmp = this._super;
|
||||
this._super = _super[name];
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
return ret;
|
||||
}
|
||||
})(name, properties[name]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.constructor = Class;
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.constructor = Class;
|
||||
|
||||
// And make this class extendable
|
||||
Class.extend = arguments.callee;
|
||||
// And make this class extendable
|
||||
Class.extend = arguments.callee;
|
||||
|
||||
return Class;
|
||||
};
|
||||
return Class;
|
||||
};
|
||||
})();
|
||||
|
||||
// todo change john resig class to keep window clean
|
||||
openerp.base.Class = window.Class
|
||||
|
||||
openerp.base.callback = function(obj, method) {
|
||||
var callback = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
@ -123,7 +151,7 @@ openerp.base.callback = function(obj, method) {
|
|||
/**
|
||||
* 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}
|
||||
|
@ -279,14 +307,14 @@ openerp.base.Registry = openerp.base.Class.extend( /** @lends openerp.base.Regis
|
|||
|
||||
/**
|
||||
* 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") {
|
||||
|
@ -348,26 +376,26 @@ openerp.base.SessionAware = openerp.base.Class.extend({
|
|||
/**
|
||||
* 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
|
||||
|
@ -376,48 +404,48 @@ openerp.base.SessionAware = openerp.base.Class.extend({
|
|||
* 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-',
|
||||
/**
|
||||
* @constructs
|
||||
* Construct the widget and set its parent if a parent is given.
|
||||
*
|
||||
* @param {Widget} parent Binds the current instance to the given Widget instance.
|
||||
*
|
||||
* @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
|
||||
|
@ -433,7 +461,7 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
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) {
|
||||
|
@ -444,7 +472,7 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
},
|
||||
/**
|
||||
* 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) {
|
||||
|
@ -455,7 +483,7 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
},
|
||||
/**
|
||||
* 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) {
|
||||
|
@ -466,7 +494,7 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
},
|
||||
/**
|
||||
* 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) {
|
||||
|
@ -477,7 +505,7 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
},
|
||||
/**
|
||||
* 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) {
|
||||
|
@ -497,8 +525,8 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param {Object} additional Additional context arguments to pass to the template.
|
||||
*/
|
||||
render: function (additional) {
|
||||
return QWeb.render(this.template, _.extend({widget: this}, additional || {}));
|
||||
|
@ -506,7 +534,7 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -546,6 +574,18 @@ openerp.base.Widget = openerp.base.SessionAware.extend({
|
|||
}
|
||||
return false;
|
||||
},
|
||||
do_notify: function() {
|
||||
if (this.widget_parent) {
|
||||
return this.widget_parent.do_notify.apply(this,arguments);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
do_warn: function() {
|
||||
if (this.widget_parent) {
|
||||
return this.widget_parent.do_warn.apply(this,arguments);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
rpc: function(url, data, success, error) {
|
||||
var def = $.Deferred().then(success, error);
|
||||
var self = this;
|
||||
|
@ -571,5 +611,282 @@ openerp.base.OldWidget = openerp.base.Widget.extend({
|
|||
}
|
||||
});
|
||||
|
||||
}
|
||||
openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{
|
||||
/**
|
||||
* @constructs
|
||||
* @param element_id to use for exception reporting
|
||||
* @param server
|
||||
* @param port
|
||||
*/
|
||||
init: function(parent, element_id, server, port) {
|
||||
this._super(parent, element_id);
|
||||
this.server = (server == undefined) ? location.hostname : server;
|
||||
this.port = (port == undefined) ? location.port : port;
|
||||
this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp";
|
||||
this.debug = true;
|
||||
this.db = "";
|
||||
this.login = "";
|
||||
this.password = "";
|
||||
this.uid = false;
|
||||
this.session_id = false;
|
||||
this.module_list = [];
|
||||
this.module_loaded = {"base": true};
|
||||
this.context = {};
|
||||
},
|
||||
start: function() {
|
||||
this.session_restore();
|
||||
},
|
||||
/**
|
||||
* Executes an RPC call, registering the provided callbacks.
|
||||
*
|
||||
* Registers a default error callback if none is provided, and handles
|
||||
* setting the correct session id and session context in the parameter
|
||||
* objects
|
||||
*
|
||||
* @param {String} url RPC endpoint
|
||||
* @param {Object} params call parameters
|
||||
* @param {Function} success_callback function to execute on RPC call success
|
||||
* @param {Function} error_callback function to execute on RPC call failure
|
||||
* @returns {jQuery.Deferred} jquery-provided ajax deferred
|
||||
*/
|
||||
rpc: function(url, params, success_callback, error_callback) {
|
||||
var self = this;
|
||||
// Construct a JSON-RPC2 request, method is currently unused
|
||||
params.session_id = this.session_id;
|
||||
|
||||
// Call using the rpc_mode
|
||||
var deferred = $.Deferred();
|
||||
this.rpc_ajax(url, {
|
||||
jsonrpc: "2.0",
|
||||
method: "call",
|
||||
params: params,
|
||||
id:null
|
||||
}).then(function () {deferred.resolve.apply(deferred, arguments);},
|
||||
function(error) {deferred.reject(error, $.Event());});
|
||||
return deferred.fail(function() {
|
||||
deferred.fail(function(error, event) {
|
||||
if (!event.isDefaultPrevented()) {
|
||||
self.on_rpc_error(error, event);
|
||||
}
|
||||
});
|
||||
}).then(success_callback, error_callback).promise();
|
||||
},
|
||||
/**
|
||||
* Raw JSON-RPC call
|
||||
*
|
||||
* @returns {jQuery.Deferred} ajax-based deferred object
|
||||
*/
|
||||
rpc_ajax: function(url, payload) {
|
||||
var self = this;
|
||||
this.on_rpc_request();
|
||||
// url can be an $.ajax option object
|
||||
if (_.isString(url)) {
|
||||
url = {
|
||||
url: url
|
||||
}
|
||||
}
|
||||
var ajax = _.extend({
|
||||
type: "POST",
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(payload),
|
||||
processData: false
|
||||
}, url);
|
||||
var deferred = $.Deferred();
|
||||
$.ajax(ajax).done(function(response, textStatus, jqXHR) {
|
||||
self.on_rpc_response();
|
||||
if (!response.error) {
|
||||
deferred.resolve(response["result"], textStatus, jqXHR);
|
||||
return;
|
||||
}
|
||||
if (response.error.data.type !== "session_invalid") {
|
||||
deferred.reject(response.error);
|
||||
return;
|
||||
}
|
||||
self.uid = false;
|
||||
self.on_session_invalid(function() {
|
||||
self.rpc(url, payload.params,
|
||||
function() {
|
||||
deferred.resolve.apply(deferred, arguments);
|
||||
},
|
||||
function(error, event) {
|
||||
event.preventDefault();
|
||||
deferred.reject.apply(deferred, arguments);
|
||||
});
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
self.on_rpc_response();
|
||||
var error = {
|
||||
code: -32098,
|
||||
message: "XmlHttpRequestError " + errorThrown,
|
||||
data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] }
|
||||
};
|
||||
deferred.reject(error);
|
||||
});
|
||||
return deferred.promise();
|
||||
},
|
||||
on_rpc_request: function() {
|
||||
},
|
||||
on_rpc_response: function() {
|
||||
},
|
||||
on_rpc_error: function(error) {
|
||||
},
|
||||
/**
|
||||
* The session is validated either by login or by restoration of a previous session
|
||||
*/
|
||||
on_session_valid: function() {
|
||||
if(!openerp._modules_loaded)
|
||||
this.load_modules();
|
||||
},
|
||||
on_session_invalid: function(contination) {
|
||||
},
|
||||
session_is_valid: function() {
|
||||
return this.uid;
|
||||
},
|
||||
session_login: function(db, login, password, success_callback) {
|
||||
var self = this;
|
||||
this.db = db;
|
||||
this.login = login;
|
||||
this.password = password;
|
||||
var params = { db: this.db, login: this.login, password: this.password };
|
||||
this.rpc("/base/session/login", params, function(result) {
|
||||
self.session_id = result.session_id;
|
||||
self.uid = result.uid;
|
||||
self.session_save();
|
||||
self.on_session_valid();
|
||||
if (success_callback)
|
||||
success_callback();
|
||||
});
|
||||
},
|
||||
session_logout: function() {
|
||||
this.uid = false;
|
||||
},
|
||||
/**
|
||||
* Reloads uid and session_id from local storage, if they exist
|
||||
*/
|
||||
session_restore: function () {
|
||||
this.uid = this.get_cookie('uid');
|
||||
this.session_id = this.get_cookie('session_id');
|
||||
this.db = this.get_cookie('db');
|
||||
this.login = this.get_cookie('login');
|
||||
// we should do an rpc to confirm that this session_id is valid and if it is retrieve the information about db and login
|
||||
// then call on_session_valid
|
||||
this.on_session_valid();
|
||||
},
|
||||
/**
|
||||
* Saves the session id and uid locally
|
||||
*/
|
||||
session_save: function () {
|
||||
this.set_cookie('uid', this.uid);
|
||||
this.set_cookie('session_id', this.session_id);
|
||||
this.set_cookie('db', this.db);
|
||||
this.set_cookie('login', this.login);
|
||||
},
|
||||
logout: function() {
|
||||
delete this.uid;
|
||||
delete this.session_id;
|
||||
delete this.db;
|
||||
delete this.login;
|
||||
this.set_cookie('uid', '');
|
||||
this.set_cookie('session_id', '');
|
||||
this.set_cookie('db', '');
|
||||
this.set_cookie('login', '');
|
||||
this.on_session_invalid(function() {});
|
||||
},
|
||||
/**
|
||||
* Fetches a cookie stored by an openerp session
|
||||
*
|
||||
* @private
|
||||
* @param name the cookie's name
|
||||
*/
|
||||
get_cookie: function (name) {
|
||||
var nameEQ = this.element_id + '|' + name + '=';
|
||||
var cookies = document.cookie.split(';');
|
||||
for(var i=0; i<cookies.length; ++i) {
|
||||
var cookie = cookies[i].replace(/^\s*/, '');
|
||||
if(cookie.indexOf(nameEQ) === 0) {
|
||||
return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
/**
|
||||
* Create a new cookie with the provided name and value
|
||||
*
|
||||
* @private
|
||||
* @param name the cookie's name
|
||||
* @param value the cookie's value
|
||||
* @param ttl the cookie's time to live, 1 year by default, set to -1 to delete
|
||||
*/
|
||||
set_cookie: function (name, value, ttl) {
|
||||
ttl = ttl || 24*60*60*365;
|
||||
document.cookie = [
|
||||
this.element_id + '|' + name + '=' + encodeURIComponent(JSON.stringify(value)),
|
||||
'max-age=' + ttl,
|
||||
'expires=' + new Date(new Date().getTime() + ttl*1000).toGMTString()
|
||||
].join(';');
|
||||
},
|
||||
/**
|
||||
* Load additional web addons of that instance and init them
|
||||
*/
|
||||
load_modules: function() {
|
||||
var self = this;
|
||||
this.rpc('/base/session/modules', {}, function(result) {
|
||||
self.module_list = result;
|
||||
var modules = self.module_list.join(',');
|
||||
if(self.debug || true) {
|
||||
self.rpc('/base/webclient/csslist', {"mods": modules}, self.do_load_css);
|
||||
self.rpc('/base/webclient/jslist', {"mods": modules}, self.do_load_js);
|
||||
} else {
|
||||
self.do_load_css(["/base/webclient/css?mods="+modules]);
|
||||
self.do_load_js(["/base/webclient/js?mods="+modules]);
|
||||
}
|
||||
openerp._modules_loaded = true;
|
||||
});
|
||||
},
|
||||
do_load_css: function (files) {
|
||||
_.each(files, function (file) {
|
||||
$('head').append($('<link>', {
|
||||
'href': file,
|
||||
'rel': 'stylesheet',
|
||||
'type': 'text/css'
|
||||
}));
|
||||
});
|
||||
},
|
||||
do_load_js: function(files) {
|
||||
var self = this;
|
||||
if(files.length != 0) {
|
||||
var file = files.shift();
|
||||
var tag = document.createElement('script');
|
||||
tag.type = 'text/javascript';
|
||||
tag.src = file;
|
||||
tag.onload = tag.onreadystatechange = function() {
|
||||
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
|
||||
return;
|
||||
tag.onload_done = true;
|
||||
self.do_load_js(files);
|
||||
};
|
||||
document.head.appendChild(tag);
|
||||
} else {
|
||||
this.on_modules_loaded();
|
||||
}
|
||||
},
|
||||
on_modules_loaded: function() {
|
||||
for(var j=0; j<this.module_list.length; j++) {
|
||||
var mod = this.module_list[j];
|
||||
if(this.module_loaded[mod])
|
||||
continue;
|
||||
openerp[mod] = {};
|
||||
// init module mod
|
||||
if(openerp._openerp[mod] != undefined) {
|
||||
openerp._openerp[mod](openerp);
|
||||
this.module_loaded[mod] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
|
|
@ -268,9 +268,13 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
},
|
||||
/**
|
||||
* Read records.
|
||||
*
|
||||
* @param {Array} ids identifiers of the records to read
|
||||
* @param {Array} fields fields to read and return, by default all fields are returned
|
||||
* @param {Function} callback function called with read result
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
read_ids: function (ids, fields, callback) {
|
||||
var self = this;
|
||||
return this.rpc('/base/dataset/get', {
|
||||
model: this.model,
|
||||
ids: ids,
|
||||
|
@ -282,13 +286,20 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
* Read a slice of the records represented by this DataSet, based on its
|
||||
* domain and context.
|
||||
*
|
||||
* @param {Number} [offset=0] The index from which selected records should be returned
|
||||
* @param {Number} [limit=null] The maximum number of records to return
|
||||
* @params {Object} options
|
||||
* @param {Array} [options.fields] fields to read and return, by default all fields are returned
|
||||
* @param {Number} [options.offset=0] The index from which selected records should be returned
|
||||
* @param {Number} [options.limit=null] The maximum number of records to return
|
||||
* @param {Function} callback function called with read_slice result
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
read_slice: function (fields, offset, limit, callback) {
|
||||
},
|
||||
read_slice: function (options, callback) { return null; },
|
||||
/**
|
||||
* Read the indexed record.
|
||||
* Reads the current dataset record (from its index)
|
||||
*
|
||||
* @params {Array} [fields] fields to read and return, by default all fields are returned
|
||||
* @params {Function} callback function called with read_index result
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
read_index: function (fields, callback) {
|
||||
var def = $.Deferred().then(callback);
|
||||
|
@ -304,6 +315,13 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
}
|
||||
return def.promise();
|
||||
},
|
||||
/**
|
||||
* Reads default values for the current model
|
||||
*
|
||||
* @param {Array} [fields] fields to get default values for, by default all defaults are read
|
||||
* @param {Function} callback function called with default_get result
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
default_get: function(fields, callback) {
|
||||
return this.rpc('/base/dataset/default_get', {
|
||||
model: this.model,
|
||||
|
@ -311,6 +329,14 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
context: this.get_context()
|
||||
}, callback);
|
||||
},
|
||||
/**
|
||||
* Creates a new record in db
|
||||
*
|
||||
* @param {Object} data field values to set on the new record
|
||||
* @param {Function} callback function called with operation result
|
||||
* @param {Function} error_callback function called in case of creation error
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
create: function(data, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/create', {
|
||||
model: this.model,
|
||||
|
@ -318,19 +344,44 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
context: this.get_context()
|
||||
}, callback, error_callback);
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
/**
|
||||
* Saves the provided data in an existing db record
|
||||
*
|
||||
* @param {Number|String} id identifier for the record to alter
|
||||
* @param {Object} data field values to write into the record
|
||||
* @param {Function} callback function called with operation result
|
||||
* @param {Function} error_callback function called in case of write error
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
write: function (id, data, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/save', {
|
||||
model: this.model,
|
||||
id: id,
|
||||
data: data,
|
||||
context: this.get_context()
|
||||
}, callback);
|
||||
}, callback, error_callback);
|
||||
},
|
||||
/**
|
||||
* Deletes an existing record from the database
|
||||
*
|
||||
* @param {Number|String} ids identifier of the record to delete
|
||||
* @param {Function} callback function called with operation result
|
||||
* @param {Function} error_callback function called in case of deletion error
|
||||
*/
|
||||
unlink: function(ids, callback, error_callback) {
|
||||
var self = this;
|
||||
return this.call_and_eval("unlink", [ids, this.get_context()], null, 1,
|
||||
callback, error_callback);
|
||||
},
|
||||
/**
|
||||
* Calls an arbitrary RPC method
|
||||
*
|
||||
* @param {String} method name of the method (on the current model) to call
|
||||
* @param {Array} [args] arguments to pass to the method
|
||||
* @param {Function} callback
|
||||
* @param {Function} error_callback
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
call: function (method, args, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/call', {
|
||||
model: this.model,
|
||||
|
@ -338,6 +389,17 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
args: args || []
|
||||
}, callback, error_callback);
|
||||
},
|
||||
/**
|
||||
* Calls an arbitrary method, with more crazy
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {Array} [args]
|
||||
* @param {Number} [domain_id] index of a domain to evaluate in the args array
|
||||
* @param {Number} [context_id] index of a context to evaluate in the args array
|
||||
* @param {Function} callback
|
||||
* @param {Function }error_callback
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
call_and_eval: function (method, args, domain_id, context_id, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/call', {
|
||||
model: this.model,
|
||||
|
@ -347,6 +409,15 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
args: args || []
|
||||
}, callback, error_callback);
|
||||
},
|
||||
/**
|
||||
* Calls a button method, usually returning some sort of action
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {Array} [args]
|
||||
* @param {Function} callback
|
||||
* @param {Function} error_callback
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
call_button: function (method, args, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/call_button', {
|
||||
model: this.model,
|
||||
|
@ -356,17 +427,34 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
args: args || []
|
||||
}, callback, error_callback);
|
||||
},
|
||||
/**
|
||||
* Fetches the "readable name" for records, based on intrinsic rules
|
||||
*
|
||||
* @param {Array} ids
|
||||
* @param {Function} callback
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
name_get: function(ids, callback) {
|
||||
return this.call_and_eval('name_get', [ids, this.get_context()], null, 1, callback);
|
||||
},
|
||||
/*
|
||||
* args = domain
|
||||
/**
|
||||
*
|
||||
* @param {String} name name to perform a search for/on
|
||||
* @param {Array} [domain=[]] filters for the objects returned, OpenERP domain
|
||||
* @param {String} [operator='ilike'] matching operator to use with the provided name value
|
||||
* @param {Number} [limit=100] maximum number of matches to return
|
||||
* @param {Function} callback function to call with name_search result
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
name_search: function (name, args, operator, limit, callback) {
|
||||
name_search: function (name, domain, operator, limit, callback) {
|
||||
return this.call_and_eval('name_search',
|
||||
[name || '', args || false, operator || 'ilike', this.get_context(), limit || 100],
|
||||
[name || '', domain || false, operator || 'ilike', this.get_context(), limit || 100],
|
||||
1, 3, callback);
|
||||
},
|
||||
/**
|
||||
* @param name
|
||||
* @param callback
|
||||
*/
|
||||
name_create: function(name, callback) {
|
||||
return this.call_and_eval('name_create', [name, this.get_context()], null, 1, callback);
|
||||
},
|
||||
|
@ -377,7 +465,10 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
|||
signal: signal
|
||||
}, callback);
|
||||
},
|
||||
get_context: function() {
|
||||
get_context: function(request_context) {
|
||||
if (request_context) {
|
||||
return new openerp.base.CompoundContext(this.context, request_context);
|
||||
}
|
||||
return this.context;
|
||||
}
|
||||
});
|
||||
|
@ -387,9 +478,11 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
|
|||
// all local records
|
||||
this.ids = ids || [];
|
||||
},
|
||||
read_slice: function (fields, offset, limit, callback) {
|
||||
var self = this;
|
||||
offset = offset || 0;
|
||||
read_slice: function (options, callback) {
|
||||
var self = this,
|
||||
offset = options.offset || 0,
|
||||
limit = options.limit || false,
|
||||
fields = options.fields || false;
|
||||
var end_pos = limit && limit !== -1 ? offset + limit : undefined;
|
||||
return this.read_ids(this.ids.slice(offset, end_pos), fields, callback);
|
||||
},
|
||||
|
@ -409,6 +502,14 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
|
|||
}
|
||||
});
|
||||
openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
||||
/**
|
||||
* @constructs
|
||||
*
|
||||
* @param {Object} parent
|
||||
* @param {String} model
|
||||
* @param {Object} context
|
||||
* @param {Array} domain
|
||||
*/
|
||||
init: function(parent, model, context, domain) {
|
||||
this._super(parent, model, context);
|
||||
this.domain = domain || [];
|
||||
|
@ -418,25 +519,30 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
|||
// is it necessary ?
|
||||
this.ids = [];
|
||||
},
|
||||
read_slice: function (fields, offset, limit, callback) {
|
||||
/**
|
||||
* Read a slice of the records represented by this DataSet, based on its
|
||||
* domain and context.
|
||||
*
|
||||
* @params {Object} options
|
||||
* @param {Array} [options.fields] fields to read and return, by default all fields are returned
|
||||
* @param {Object} [options.context] context data to add to the request payload, on top of the DataSet's own context
|
||||
* @param {Array} [options.domain] domain data to add to the request payload, ANDed with the dataset's domain
|
||||
* @param {Number} [options.offset=0] The index from which selected records should be returned
|
||||
* @param {Number} [options.limit=null] The maximum number of records to return
|
||||
* @param {Function} callback function called with read_slice result
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
read_slice: function (options, callback) {
|
||||
var self = this;
|
||||
offset = offset || 0;
|
||||
// cached search, not sure it's a good idea
|
||||
if(this.offset <= offset) {
|
||||
var start = offset - this.offset;
|
||||
if(this.ids.length - start >= limit) {
|
||||
// TODO: check if this could work do only read if possible
|
||||
// return read_ids(ids.slice(start,start+limit),fields,callback)
|
||||
}
|
||||
}
|
||||
var offset = options.offset || 0;
|
||||
return this.rpc('/base/dataset/search_read', {
|
||||
model: this.model,
|
||||
fields: fields,
|
||||
domain: this.domain,
|
||||
context: this.get_context(),
|
||||
fields: options.fields || false,
|
||||
domain: this.get_domain(options.domain),
|
||||
context: this.get_context(options.context),
|
||||
sort: this.sort(),
|
||||
offset: offset,
|
||||
limit: limit
|
||||
limit: options.limit || false
|
||||
}, function (result) {
|
||||
self.ids = result.ids;
|
||||
self.offset = offset;
|
||||
|
@ -445,6 +551,12 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
|||
}
|
||||
});
|
||||
},
|
||||
get_domain: function (other_domain) {
|
||||
if (other_domain) {
|
||||
return new openerp.base.CompoundDomain(this.domain, other_domain);
|
||||
}
|
||||
return this.domain;
|
||||
},
|
||||
/**
|
||||
* Reads or changes sort criteria on the dataset.
|
||||
*
|
||||
|
@ -620,48 +732,51 @@ openerp.base.ReadOnlyDataSetSearch = openerp.base.DataSetSearch.extend({
|
|||
on_unlink: function(ids) {}
|
||||
});
|
||||
|
||||
openerp.base.CompoundContext = function() {
|
||||
this.__ref = "compound_context";
|
||||
this.__contexts = [];
|
||||
this.__eval_context = null;
|
||||
var self = this;
|
||||
_.each(arguments, function(x) {
|
||||
self.add(x);
|
||||
});
|
||||
};
|
||||
openerp.base.CompoundContext.prototype.add = function(context) {
|
||||
this.__contexts.push(context);
|
||||
return this;
|
||||
};
|
||||
openerp.base.CompoundContext.prototype.set_eval_context = function(eval_context) {
|
||||
this.__eval_context = eval_context;
|
||||
return this;
|
||||
};
|
||||
openerp.base.CompoundContext.prototype.get_eval_context = function() {
|
||||
return this.__eval_context;
|
||||
};
|
||||
|
||||
openerp.base.CompoundDomain = function() {
|
||||
this.__ref = "compound_domain";
|
||||
this.__domains = [];
|
||||
this.__eval_context = null;
|
||||
var self = this;
|
||||
_.each(arguments, function(x) {
|
||||
self.add(x);
|
||||
});
|
||||
};
|
||||
openerp.base.CompoundDomain.prototype.add = function(domain) {
|
||||
this.__domains.push(domain);
|
||||
return this;
|
||||
};
|
||||
openerp.base.CompoundDomain.prototype.set_eval_context = function(eval_context) {
|
||||
this.__eval_context = eval_context;
|
||||
return this;
|
||||
};
|
||||
openerp.base.CompoundDomain.prototype.get_eval_context = function() {
|
||||
return this.__eval_context;
|
||||
};
|
||||
openerp.base.CompoundContext = openerp.base.Class.extend({
|
||||
init: function () {
|
||||
this.__ref = "compound_context";
|
||||
this.__contexts = [];
|
||||
this.__eval_context = null;
|
||||
var self = this;
|
||||
_.each(arguments, function(x) {
|
||||
self.add(x);
|
||||
});
|
||||
},
|
||||
add: function (context) {
|
||||
this.__contexts.push(context);
|
||||
return this;
|
||||
},
|
||||
set_eval_context: function (eval_context) {
|
||||
this.__eval_context = eval_context;
|
||||
return this;
|
||||
},
|
||||
get_eval_context: function () {
|
||||
return this.__eval_context;
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.CompoundDomain = openerp.base.Class.extend({
|
||||
init: function () {
|
||||
this.__ref = "compound_domain";
|
||||
this.__domains = [];
|
||||
this.__eval_context = null;
|
||||
var self = this;
|
||||
_.each(arguments, function(x) {
|
||||
self.add(x);
|
||||
});
|
||||
},
|
||||
add: function(domain) {
|
||||
this.__domains.push(domain);
|
||||
return this;
|
||||
},
|
||||
set_eval_context: function(eval_context) {
|
||||
this.__eval_context = eval_context;
|
||||
return this;
|
||||
},
|
||||
get_eval_context: function() {
|
||||
return this.__eval_context;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
|
||||
openerp.base.dates = function(openerp) {
|
||||
|
||||
/**
|
||||
* Converts a string to a Date javascript object using OpenERP's
|
||||
* datetime string format (exemple: '2011-12-01 15:12:35').
|
||||
*
|
||||
* The timezone is assumed to be UTC (standard for OpenERP 6.1)
|
||||
* and will be converted to the browser's timezone.
|
||||
*
|
||||
* @param {String} str A string representing a datetime.
|
||||
* @returns {Date}
|
||||
*/
|
||||
openerp.base.parse_datetime = function(str) {
|
||||
if(!str) {
|
||||
return str;
|
||||
}
|
||||
var regex = /\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/;
|
||||
var res = regex.exec(str);
|
||||
if ( res[0] != str ) {
|
||||
throw "'" + str + "' is not a valid datetime";
|
||||
}
|
||||
var obj = Date.parse(str + " GMT");
|
||||
if (! obj) {
|
||||
throw "'" + str + "' is not a valid datetime";
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a string to a Date javascript object using OpenERP's
|
||||
* date string format (exemple: '2011-12-01').
|
||||
*
|
||||
* @param {String} str A string representing a date.
|
||||
* @returns {Date}
|
||||
*/
|
||||
openerp.base.parse_date = function(str) {
|
||||
if(!str) {
|
||||
return str;
|
||||
}
|
||||
var regex = /\d\d\d\d-\d\d-\d\d/;
|
||||
var res = regex.exec(str);
|
||||
if ( res[0] != str ) {
|
||||
throw "'" + str + "' is not a valid date";
|
||||
}
|
||||
var obj = Date.parse(str);
|
||||
if (! obj) {
|
||||
throw "'" + str + "' is not a valid date";
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a string to a Date javascript object using OpenERP's
|
||||
* time string format (exemple: '15:12:35').
|
||||
*
|
||||
* @param {String} str A string representing a time.
|
||||
* @returns {Date}
|
||||
*/
|
||||
openerp.base.parse_time = function(str) {
|
||||
if(!str) {
|
||||
return str;
|
||||
}
|
||||
var regex = /\d\d:\d\d:\d\d/;
|
||||
var res = regex.exec(str);
|
||||
if ( res[0] != str ) {
|
||||
throw "'" + str + "' is not a valid time";
|
||||
}
|
||||
var obj = Date.parse(str);
|
||||
if (! obj) {
|
||||
throw "'" + str + "' is not a valid time";
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/*
|
||||
* Just a simple function to add some '0' if an integer it too small.
|
||||
*/
|
||||
var fts = function(str, size) {
|
||||
str = "" + str;
|
||||
var to_add = "";
|
||||
_.each(_.range(size - str.length), function() {
|
||||
to_add = to_add + "0";
|
||||
});
|
||||
return to_add + str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Date javascript object to a string using OpenERP's
|
||||
* datetime string format (exemple: '2011-12-01 15:12:35').
|
||||
*
|
||||
* The timezone of the Date object is assumed to be the one of the
|
||||
* browser and it will be converted to UTC (standard for OpenERP 6.1).
|
||||
*
|
||||
* @param {Date} obj
|
||||
* @returns {String} A string representing a datetime.
|
||||
*/
|
||||
openerp.base.format_datetime = function(obj) {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
return fts(obj.getUTCFullYear(),4) + "-" + fts(obj.getUTCMonth() + 1,2) + "-"
|
||||
+ fts(obj.getUTCDate(),2) + " " + fts(obj.getUTCHours(),2) + ":"
|
||||
+ fts(obj.getUTCMinutes(),2) + ":" + fts(obj.getUTCSeconds(),2);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Date javascript object to a string using OpenERP's
|
||||
* date string format (exemple: '2011-12-01').
|
||||
*
|
||||
* @param {Date} obj
|
||||
* @returns {String} A string representing a date.
|
||||
*/
|
||||
openerp.base.format_date = function(obj) {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
return fts(obj.getFullYear(),4) + "-" + fts(obj.getMonth() + 1,2) + "-"
|
||||
+ fts(obj.getDate(),2);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Date javascript object to a string using OpenERP's
|
||||
* time string format (exemple: '15:12:35').
|
||||
*
|
||||
* @param {Date} obj
|
||||
* @returns {String} A string representing a time.
|
||||
*/
|
||||
openerp.base.format_time = function(obj) {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
return fts(obj.getHours(),2) + ":" + fts(obj.getMinutes(),2) + ":"
|
||||
+ fts(obj.getSeconds(),2);
|
||||
};
|
||||
|
||||
};
|
|
@ -19,7 +19,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
|||
*/
|
||||
init: function(parent, element_id, dataset, view_id, options) {
|
||||
this._super(parent, element_id);
|
||||
this.set_default_options();
|
||||
this.set_default_options(options);
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
|
@ -36,7 +36,6 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
|||
this.registry = openerp.base.form.widgets;
|
||||
this.has_been_loaded = $.Deferred();
|
||||
this.$form_header = null;
|
||||
this.options = options || {};
|
||||
_.defaults(this.options, {"always_show_new_button": true});
|
||||
},
|
||||
start: function() {
|
||||
|
@ -156,7 +155,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
|||
if (this.sidebar) {
|
||||
this.sidebar.attachments.do_update();
|
||||
}
|
||||
if (this.default_focus_field) {
|
||||
if (this.default_focus_field && !this.embedded_view) {
|
||||
this.default_focus_field.focus();
|
||||
}
|
||||
},
|
||||
|
@ -452,12 +451,14 @@ openerp.base.form.SidebarAttachments = openerp.base.Widget.extend({
|
|||
this.on_attachments_loaded([]);
|
||||
} else {
|
||||
(new openerp.base.DataSetSearch(
|
||||
this, 'ir.attachment', this.view.dataset.get_context(),
|
||||
[['res_model', '=', this.view.dataset.model],
|
||||
['res_id', '=', this.view.datarecord.id],
|
||||
['type', 'in', ['binary', 'url']]])).read_slice(
|
||||
['name', 'url', 'type'], false, false,
|
||||
this.on_attachments_loaded);
|
||||
this, 'ir.attachment', this.view.dataset.get_context(),
|
||||
[
|
||||
['res_model', '=', this.view.dataset.model],
|
||||
['res_id', '=', this.view.datarecord.id],
|
||||
['type', 'in', ['binary', 'url']]
|
||||
])).read_slice(
|
||||
{fields: ['name', 'url', 'type']},
|
||||
this.on_attachments_loaded);
|
||||
}
|
||||
},
|
||||
on_attachments_loaded: function(attachments) {
|
||||
|
@ -511,42 +512,46 @@ openerp.base.form.compute_domain = function(expr, fields) {
|
|||
}
|
||||
}
|
||||
|
||||
var field = fields[ex[0]].get_value ? fields[ex[0]].get_value() : fields[ex[0]].value;
|
||||
var field = fields[ex[0]];
|
||||
if (!field) {
|
||||
throw new Error("Domain references unknown field : " + ex[0]);
|
||||
}
|
||||
var field_value = field.get_value ? fields[ex[0]].get_value() : fields[ex[0]].value;
|
||||
var op = ex[1];
|
||||
var val = ex[2];
|
||||
|
||||
switch (op.toLowerCase()) {
|
||||
case '=':
|
||||
case '==':
|
||||
stack.push(field == val);
|
||||
stack.push(field_value == val);
|
||||
break;
|
||||
case '!=':
|
||||
case '<>':
|
||||
stack.push(field != val);
|
||||
stack.push(field_value != val);
|
||||
break;
|
||||
case '<':
|
||||
stack.push(field < val);
|
||||
stack.push(field_value < val);
|
||||
break;
|
||||
case '>':
|
||||
stack.push(field > val);
|
||||
stack.push(field_value > val);
|
||||
break;
|
||||
case '<=':
|
||||
stack.push(field <= val);
|
||||
stack.push(field_value <= val);
|
||||
break;
|
||||
case '>=':
|
||||
stack.push(field >= val);
|
||||
stack.push(field_value >= val);
|
||||
break;
|
||||
case 'in':
|
||||
stack.push(_(val).contains(field));
|
||||
stack.push(_(val).contains(field_value));
|
||||
break;
|
||||
case 'not in':
|
||||
stack.push(!_(val).contains(field));
|
||||
stack.push(!_(val).contains(field_value));
|
||||
break;
|
||||
default:
|
||||
this.log("Unsupported operator in modifiers :", op);
|
||||
}
|
||||
}
|
||||
return _.all(stack);
|
||||
return _.all(stack, _.identity);
|
||||
};
|
||||
|
||||
openerp.base.form.Widget = openerp.base.Widget.extend({
|
||||
|
@ -679,6 +684,16 @@ openerp.base.form.WidgetNotebook = openerp.base.form.Widget.extend({
|
|||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.tabs();
|
||||
this.view.on_button_new.add_last(this.do_select_first_visible_tab);
|
||||
},
|
||||
do_select_first_visible_tab: function() {
|
||||
for (var i = 0; i < this.pages.length; i++) {
|
||||
var page = this.pages[i];
|
||||
if (page.invisible === false) {
|
||||
this.$element.tabs('select', page.index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -696,8 +711,8 @@ openerp.base.form.WidgetNotebookPage = openerp.base.form.WidgetFrame.extend({
|
|||
this.$element_tab = $('#' + this.element_tab_id);
|
||||
},
|
||||
update_dom: function() {
|
||||
if (this.invisible) {
|
||||
this.notebook.$element.tabs('select', 0);
|
||||
if (this.invisible && this.index === this.notebook.$element.tabs('option', 'selected')) {
|
||||
this.notebook.do_select_first_visible_tab();
|
||||
}
|
||||
this.$element_tab.toggle(!this.invisible);
|
||||
this.$element.toggle(!this.invisible);
|
||||
|
@ -758,8 +773,7 @@ openerp.base.form.WidgetButton = openerp.base.form.Widget.extend({
|
|||
var self = this;
|
||||
|
||||
this.view.execute_action(
|
||||
this.node.attrs, this.view.dataset, this.session.action_manager,
|
||||
this.view.datarecord.id, function () {
|
||||
this.node.attrs, this.view.dataset, this.view.datarecord.id, function () {
|
||||
self.view.reload();
|
||||
});
|
||||
}
|
||||
|
@ -788,6 +802,14 @@ openerp.base.form.WidgetLabel = openerp.base.form.Widget.extend({
|
|||
}
|
||||
// Actual label widgets should not have a false and have type label
|
||||
return QWeb.render(this.template, {widget: this});
|
||||
},
|
||||
start: function() {
|
||||
this._super();
|
||||
var self = this;
|
||||
this.$element.find("label").dblclick(function() {
|
||||
var widget = self['for'] || self;
|
||||
self.log(widget.element_id , widget);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1298,7 +1320,7 @@ openerp.base.form.dialog = function(content, options) {
|
|||
}, options || {});
|
||||
options.autoOpen = true;
|
||||
var dialog = new openerp.base.Dialog(null, options);
|
||||
dialog.$dialog = $(content).dialog(dialog.options);
|
||||
dialog.$dialog = $(content).dialog(dialog.dialog_options);
|
||||
return dialog.$dialog;
|
||||
}
|
||||
|
||||
|
@ -1484,7 +1506,6 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
|||
var dataset = new openerp.base.DataSetStatic(self, self.field.relation, self.build_context());
|
||||
dataset.name_get([element_ids[0]], function(data) {
|
||||
self._change_int_ext_value(data[0]);
|
||||
pop.stop();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -1616,20 +1637,22 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
|||
modes = !!modes ? modes.split(",") : ["tree", "form"];
|
||||
var views = [];
|
||||
_.each(modes, function(mode) {
|
||||
var view = {view_id: false, view_type: mode == "tree" ? "list" : mode};
|
||||
var view = {
|
||||
view_id: false,
|
||||
view_type: mode == "tree" ? "list" : mode,
|
||||
options: { sidebar : false }
|
||||
};
|
||||
if (self.field.views && self.field.views[mode]) {
|
||||
view.embedded_view = self.field.views[mode];
|
||||
}
|
||||
if(view.view_type === "list") {
|
||||
view.options = {
|
||||
'selectable': self.multi_selection
|
||||
};
|
||||
view.options.selectable = self.multi_selection;
|
||||
}
|
||||
views.push(view);
|
||||
});
|
||||
this.views = views;
|
||||
|
||||
this.viewmanager = new openerp.base.ViewManager(this, this.element_id, this.dataset, views);
|
||||
this.viewmanager = new openerp.base.ViewManager(this, this.dataset, views);
|
||||
this.viewmanager.registry = openerp.base.views.clone({
|
||||
list: 'openerp.base.form.One2ManyListView',
|
||||
form: 'openerp.base.form.One2ManyFormView'
|
||||
|
@ -1655,7 +1678,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
|||
self.save_form_view();
|
||||
});
|
||||
setTimeout(function () {
|
||||
self.viewmanager.start();
|
||||
self.viewmanager.appendTo(self.$element);
|
||||
}, 0);
|
||||
},
|
||||
reload_current_view: function() {
|
||||
|
@ -1818,16 +1841,16 @@ openerp.base.form.One2ManyListView = openerp.base.ListView.extend({
|
|||
pop.select_element(self.o2m.field.relation,{
|
||||
initial_view: "form",
|
||||
alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
|
||||
auto_create: false,
|
||||
create_function: function(data) {
|
||||
return self.o2m.dataset.create(data, function(r) {
|
||||
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r.result]));
|
||||
self.o2m.dataset.on_change();
|
||||
});
|
||||
},
|
||||
parent_view: self.o2m.view
|
||||
}, self.o2m.build_domain(), self.o2m.build_context());
|
||||
pop.on_create.add(function(data) {
|
||||
self.o2m.dataset.create(data, function(r) {
|
||||
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r.result]));
|
||||
self.o2m.dataset.on_change();
|
||||
pop.stop();
|
||||
self.o2m.reload_current_view();
|
||||
});
|
||||
pop.on_select_elements.add_last(function() {
|
||||
self.o2m.reload_current_view();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -1866,7 +1889,7 @@ openerp.base.form.FieldMany2Many = openerp.base.form.Field.extend({
|
|||
self.on_ui_change();
|
||||
});
|
||||
|
||||
this.list_view = new openerp.base.form.Many2ManyListView(new openerp.base.NullViewManager(this), this.list_id, this.dataset, false, {
|
||||
this.list_view = new openerp.base.form.Many2ManyListView(this, this.list_id, this.dataset, false, {
|
||||
'addable': 'Add',
|
||||
'selectable': self.multi_selection
|
||||
});
|
||||
|
@ -1922,7 +1945,6 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({
|
|||
self.reload_content();
|
||||
}
|
||||
});
|
||||
pop.stop();
|
||||
});
|
||||
},
|
||||
do_activate_record: function(index, id) {
|
||||
|
@ -1944,16 +1966,22 @@ openerp.base.form.SelectCreatePopup = openerp.base.OldWidget.extend({
|
|||
* - initial_view: form or search (default search)
|
||||
* - disable_multiple_selection
|
||||
* - alternative_form_view
|
||||
* - auto_create (default true)
|
||||
* - create_function (defaults to a naive saving behavior)
|
||||
* - parent_view
|
||||
*/
|
||||
select_element: function(model, options, domain, context) {
|
||||
var self = this;
|
||||
this.model = model;
|
||||
this.domain = domain || [];
|
||||
this.context = context || {};
|
||||
this.options = _.defaults(options || {}, {"initial_view": "search", "auto_create": true});
|
||||
this.options = _.defaults(options || {}, {"initial_view": "search", "create_function": function() {
|
||||
return self.create_row.apply(self, arguments);
|
||||
}});
|
||||
this.initial_ids = this.options.initial_ids;
|
||||
openerp.base.form.dialog(this.render());
|
||||
this.created_elements = [];
|
||||
openerp.base.form.dialog(this.render(), {close:function() {
|
||||
self.check_exit();
|
||||
}});
|
||||
this.start();
|
||||
},
|
||||
start: function() {
|
||||
|
@ -1999,6 +2027,7 @@ openerp.base.form.SelectCreatePopup = openerp.base.OldWidget.extend({
|
|||
}
|
||||
$sbutton.click(function() {
|
||||
self.on_select_elements(self.selected_ids);
|
||||
self.stop();
|
||||
});
|
||||
self.view_list = new openerp.base.form.SelectCreateListView(self,
|
||||
self.element_id + "_view_list", self.dataset, false,
|
||||
|
@ -2011,15 +2040,11 @@ openerp.base.form.SelectCreatePopup = openerp.base.OldWidget.extend({
|
|||
});
|
||||
this.searchview.start();
|
||||
},
|
||||
on_create: function(data) {
|
||||
if (!this.options.auto_create)
|
||||
return;
|
||||
create_row: function(data) {
|
||||
var self = this;
|
||||
var wdataset = new openerp.base.DataSetSearch(this, this.model, this.context, this.domain);
|
||||
wdataset.parent_view = this.options.parent_view;
|
||||
wdataset.create(data, function(r) {
|
||||
self.on_select_elements([r.result]);
|
||||
});
|
||||
return wdataset.create(data);
|
||||
},
|
||||
on_select_elements: function(element_ids) {
|
||||
},
|
||||
|
@ -2047,18 +2072,43 @@ openerp.base.form.SelectCreatePopup = openerp.base.OldWidget.extend({
|
|||
this.view_form.start();
|
||||
this.view_form.on_loaded.add_last(function() {
|
||||
var $buttons = self.view_form.$element.find(".oe_form_buttons");
|
||||
$buttons.html(QWeb.render("SelectCreatePopup.form.buttons"));
|
||||
$buttons.html(QWeb.render("SelectCreatePopup.form.buttons", {widget:self}));
|
||||
var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save-new");
|
||||
$nbutton.click(function() {
|
||||
self._created = $.Deferred().then(function() {
|
||||
self._created = undefined;
|
||||
self.view_form.on_button_new();
|
||||
});
|
||||
self.view_form.do_save();
|
||||
});
|
||||
var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save");
|
||||
$nbutton.click(function() {
|
||||
self._created = $.Deferred().then(function() {
|
||||
self._created = undefined;
|
||||
self.check_exit();
|
||||
});
|
||||
self.view_form.do_save();
|
||||
});
|
||||
var $cbutton = $buttons.find(".oe_selectcreatepopup-form-close");
|
||||
$cbutton.click(function() {
|
||||
self.stop();
|
||||
self.check_exit();
|
||||
});
|
||||
});
|
||||
this.dataset.on_create.add(function(data) {
|
||||
self.options.create_function(data).then(function(r) {
|
||||
self.created_elements.push(r.result);
|
||||
if (self._created) {
|
||||
self._created.resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
this.dataset.on_create.add(this.on_create);
|
||||
this.view_form.do_show();
|
||||
},
|
||||
check_exit: function() {
|
||||
if (this.created_elements.length > 0) {
|
||||
this.on_select_elements(this.created_elements);
|
||||
}
|
||||
this.stop();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2068,6 +2118,7 @@ openerp.base.form.SelectCreateListView = openerp.base.ListView.extend({
|
|||
},
|
||||
select_record: function(index) {
|
||||
this.popup.on_select_elements([this.dataset.ids[index]]);
|
||||
this.popup.stop();
|
||||
},
|
||||
do_select: function(ids, records) {
|
||||
this._super(ids, records);
|
||||
|
@ -2191,8 +2242,8 @@ openerp.base.form.FieldBinary = openerp.base.form.Field.extend({
|
|||
delete(window[this.iframe]);
|
||||
if (size === false) {
|
||||
this.notification.warn("File Upload", "There was a problem while uploading your file");
|
||||
// TODO: use openerp web exception handler
|
||||
console.log("Error while uploading file : ", name);
|
||||
// TODO: use openerp web crashmanager
|
||||
this.log("Error while uploading file : ", name);
|
||||
} else {
|
||||
this.on_file_uploaded_and_valid.apply(this, arguments);
|
||||
this.on_ui_change();
|
||||
|
@ -2301,10 +2352,8 @@ openerp.base.form.widgets = new openerp.base.Registry({
|
|||
'url' : 'openerp.base.form.FieldUrl',
|
||||
'text' : 'openerp.base.form.FieldText',
|
||||
'text_wiki' : 'openerp.base.form.FieldText',
|
||||
// 'date' : 'openerp.base.form.FieldDate',
|
||||
// 'datetime' : 'openerp.base.form.FieldDatetime',
|
||||
'date' : 'openerp.base.form.FieldChar',
|
||||
'datetime' : 'openerp.base.form.FieldChar',
|
||||
'date' : 'openerp.base.form.FieldDate',
|
||||
'datetime' : 'openerp.base.form.FieldDatetime',
|
||||
'selection' : 'openerp.base.form.FieldSelection',
|
||||
'many2one' : 'openerp.base.form.FieldMany2One',
|
||||
'many2many' : 'openerp.base.form.FieldMany2Many',
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
|
||||
openerp.base.formats = function(openerp) {
|
||||
|
||||
/**
|
||||
* Converts a string to a Date javascript object using OpenERP's
|
||||
* datetime string format (exemple: '2011-12-01 15:12:35').
|
||||
*
|
||||
* The timezone is assumed to be UTC (standard for OpenERP 6.1)
|
||||
* and will be converted to the browser's timezone.
|
||||
*
|
||||
* @param {String} str A string representing a datetime.
|
||||
* @returns {Date}
|
||||
*/
|
||||
openerp.base.parse_datetime = function(str) {
|
||||
if(!str) {
|
||||
return str;
|
||||
}
|
||||
var regex = /\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/;
|
||||
var res = regex.exec(str);
|
||||
if ( res[0] != str ) {
|
||||
throw "'" + str + "' is not a valid datetime";
|
||||
}
|
||||
var obj = Date.parse(str + " GMT");
|
||||
if (! obj) {
|
||||
throw "'" + str + "' is not a valid datetime";
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a string to a Date javascript object using OpenERP's
|
||||
* date string format (exemple: '2011-12-01').
|
||||
*
|
||||
* @param {String} str A string representing a date.
|
||||
* @returns {Date}
|
||||
*/
|
||||
openerp.base.parse_date = function(str) {
|
||||
if(!str) {
|
||||
return str;
|
||||
}
|
||||
var regex = /\d\d\d\d-\d\d-\d\d/;
|
||||
var res = regex.exec(str);
|
||||
if ( res[0] != str ) {
|
||||
throw "'" + str + "' is not a valid date";
|
||||
}
|
||||
var obj = Date.parse(str);
|
||||
if (! obj) {
|
||||
throw "'" + str + "' is not a valid date";
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a string to a Date javascript object using OpenERP's
|
||||
* time string format (exemple: '15:12:35').
|
||||
*
|
||||
* @param {String} str A string representing a time.
|
||||
* @returns {Date}
|
||||
*/
|
||||
openerp.base.parse_time = function(str) {
|
||||
if(!str) {
|
||||
return str;
|
||||
}
|
||||
var regex = /\d\d:\d\d:\d\d/;
|
||||
var res = regex.exec(str);
|
||||
if ( res[0] != str ) {
|
||||
throw "'" + str + "' is not a valid time";
|
||||
}
|
||||
var obj = Date.parse(str);
|
||||
if (! obj) {
|
||||
throw "'" + str + "' is not a valid time";
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/*
|
||||
* Left-pad provided arg 1 with zeroes until reaching size provided by second
|
||||
* argument.
|
||||
*
|
||||
* @param {Number|String} str value to pad
|
||||
* @param {Number} size size to reach on the final padded value
|
||||
* @returns {String} padded string
|
||||
*/
|
||||
var zpad = function(str, size) {
|
||||
str = "" + str;
|
||||
return new Array(size - str.length).join('0') + str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Date javascript object to a string using OpenERP's
|
||||
* datetime string format (exemple: '2011-12-01 15:12:35').
|
||||
*
|
||||
* The timezone of the Date object is assumed to be the one of the
|
||||
* browser and it will be converted to UTC (standard for OpenERP 6.1).
|
||||
*
|
||||
* @param {Date} obj
|
||||
* @returns {String} A string representing a datetime.
|
||||
*/
|
||||
openerp.base.format_datetime = function(obj) {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
return zpad(obj.getUTCFullYear(),4) + "-" + zpad(obj.getUTCMonth() + 1,2) + "-"
|
||||
+ zpad(obj.getUTCDate(),2) + " " + zpad(obj.getUTCHours(),2) + ":"
|
||||
+ zpad(obj.getUTCMinutes(),2) + ":" + zpad(obj.getUTCSeconds(),2);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Date javascript object to a string using OpenERP's
|
||||
* date string format (exemple: '2011-12-01').
|
||||
*
|
||||
* @param {Date} obj
|
||||
* @returns {String} A string representing a date.
|
||||
*/
|
||||
openerp.base.format_date = function(obj) {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
return zpad(obj.getFullYear(),4) + "-" + zpad(obj.getMonth() + 1,2) + "-"
|
||||
+ zpad(obj.getDate(),2);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Date javascript object to a string using OpenERP's
|
||||
* time string format (exemple: '15:12:35').
|
||||
*
|
||||
* @param {Date} obj
|
||||
* @returns {String} A string representing a time.
|
||||
*/
|
||||
openerp.base.format_time = function(obj) {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
return zpad(obj.getHours(),2) + ":" + zpad(obj.getMinutes(),2) + ":"
|
||||
+ zpad(obj.getSeconds(),2);
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats a single atomic value based on a field descriptor
|
||||
*
|
||||
* @param {Object} value read from OpenERP
|
||||
* @param {Object} descriptor union of orm field and view field
|
||||
* @param {Object} [descriptor.widget] widget to use to display the value
|
||||
* @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
|
||||
* @param {Object} [descriptor.digits] used for the formatting of floats
|
||||
* @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
|
||||
*/
|
||||
openerp.base.format_value = function (value, descriptor, value_if_empty) {
|
||||
// If NaN value, display as with a `false` (empty cell)
|
||||
if (typeof value === 'number' && isNaN(value)) {
|
||||
value = false;
|
||||
}
|
||||
switch (value) {
|
||||
case false:
|
||||
case Infinity:
|
||||
case -Infinity:
|
||||
return value_if_empty === undefined ? '' : value_if_empty;
|
||||
}
|
||||
switch (descriptor.widget || descriptor.type) {
|
||||
case 'integer':
|
||||
return _.sprintf('%d', value);
|
||||
case 'float':
|
||||
var precision = descriptor.digits ? descriptor.digits[1] : 2;
|
||||
return _.sprintf('%.' + precision + 'f', value);
|
||||
case 'float_time':
|
||||
return _.sprintf("%02d:%02d",
|
||||
Math.floor(value),
|
||||
Math.round((value % 1) * 60));
|
||||
case 'progressbar':
|
||||
return _.sprintf(
|
||||
'<progress value="%.2f" max="100.0">%.2f%%</progress>',
|
||||
value, value);
|
||||
case 'many2one':
|
||||
// name_get value format
|
||||
return value[1];
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats a provided cell based on its field type
|
||||
*
|
||||
* @param {Object} row_data record whose values should be displayed in the cell
|
||||
* @param {Object} column column descriptor
|
||||
* @param {"button"|"field"} column.tag base control type
|
||||
* @param {String} column.type widget type for a field control
|
||||
* @param {String} [column.string] button label
|
||||
* @param {String} [column.icon] button icon
|
||||
* @param {String} [value_if_empty=''] what to display if the field's value is ``false``
|
||||
*/
|
||||
openerp.base.format_cell = function (row_data, column, value_if_empty) {
|
||||
var attrs = column.modifiers_for(row_data);
|
||||
if (attrs.invisible) { return ''; }
|
||||
if (column.tag === 'button') {
|
||||
return [
|
||||
'<button type="button" title="', column.string || '', '">',
|
||||
'<img src="/base/static/src/img/icons/', column.icon, '.png"',
|
||||
' alt="', column.string || '', '"/>',
|
||||
'</button>'
|
||||
].join('')
|
||||
}
|
||||
|
||||
return openerp.base.format_value(
|
||||
row_data[column.id].value, column, value_if_empty);
|
||||
}
|
||||
|
||||
};
|
|
@ -8,15 +8,11 @@ openerp.base.list.editable = function (openerp) {
|
|||
// editability status of list rows
|
||||
openerp.base.ListView.prototype.defaults.editable = null;
|
||||
|
||||
var old_init = openerp.base.ListView.prototype.init,
|
||||
old_actual_search = openerp.base.ListView.prototype.do_actual_search,
|
||||
old_add_record = openerp.base.ListView.prototype.do_add_record,
|
||||
old_on_loaded = openerp.base.ListView.prototype.on_loaded;
|
||||
// TODO: not sure second @lends on existing item is correct, to check
|
||||
_.extend(openerp.base.ListView.prototype, /** @lends openerp.base.ListView# */{
|
||||
openerp.base.ListView.include(/** @lends openerp.base.ListView# */{
|
||||
init: function () {
|
||||
var self = this;
|
||||
old_init.apply(this, arguments);
|
||||
this._super.apply(this, arguments);
|
||||
$(this.groups).bind({
|
||||
'edit': function (e, id, dataset) {
|
||||
self.do_edit(dataset.index, id, dataset);
|
||||
|
@ -63,7 +59,7 @@ openerp.base.list.editable = function (openerp) {
|
|||
*/
|
||||
do_actual_search: function (results) {
|
||||
this.set_editable(results.context['set_editable']);
|
||||
old_actual_search.call(this, results);
|
||||
this._super(results);
|
||||
},
|
||||
/**
|
||||
* Replace do_add_record to handle editability (and adding new record
|
||||
|
@ -73,17 +69,17 @@ openerp.base.list.editable = function (openerp) {
|
|||
if (this.options.editable) {
|
||||
this.groups.new_record();
|
||||
} else {
|
||||
old_add_record.call(this);
|
||||
this._super();
|
||||
}
|
||||
},
|
||||
on_loaded: function (data, grouped) {
|
||||
// tree/@editable takes priority on everything else if present.
|
||||
this.options.editable = data.fields_view.arch.attrs.editable || this.options.editable;
|
||||
return old_on_loaded.call(this, data, grouped);
|
||||
return this._super(data, grouped);
|
||||
}
|
||||
});
|
||||
|
||||
_.extend(openerp.base.ListView.Groups.prototype, /** @lends openerp.base.ListView.Groups# */{
|
||||
openerp.base.ListView.Groups.include(/** @lends openerp.base.ListView.Groups# */{
|
||||
passtrough_events: openerp.base.ListView.Groups.prototype.passtrough_events + " edit saved",
|
||||
new_record: function () {
|
||||
// TODO: handle multiple children
|
||||
|
@ -91,11 +87,10 @@ openerp.base.list.editable = function (openerp) {
|
|||
}
|
||||
});
|
||||
|
||||
var old_list_row_clicked = openerp.base.ListView.List.prototype.row_clicked;
|
||||
_.extend(openerp.base.ListView.List.prototype, /** @lends openerp.base.ListView.List */{
|
||||
openerp.base.ListView.List.include(/** @lends openerp.base.ListView.List */{
|
||||
row_clicked: function (event) {
|
||||
if (!this.options.editable) {
|
||||
return old_list_row_clicked.call(this, event);
|
||||
return this._super(event);
|
||||
}
|
||||
this.edit_record();
|
||||
},
|
||||
|
@ -147,7 +142,7 @@ openerp.base.list.editable = function (openerp) {
|
|||
this.cancel_pending_edition().then(function () {
|
||||
var $new_row = $('<tr>', {
|
||||
id: _.uniqueId('oe-editable-row-'),
|
||||
'class': $(row).attr('class'),
|
||||
'class': $(row).attr('class') + ' oe_forms',
|
||||
click: function (e) {e.stopPropagation();}
|
||||
})
|
||||
.delegate('button.oe-edit-row-save', 'click', function () {
|
||||
|
@ -181,8 +176,7 @@ openerp.base.list.editable = function (openerp) {
|
|||
self.edition = true;
|
||||
self.edition_index = self.dataset.index;
|
||||
self.edition_form = _.extend(new openerp.base.FormView(
|
||||
null, self.group.view.session, $new_row.attr('id'),
|
||||
self.dataset, false), {
|
||||
self, $new_row.attr('id'), self.dataset, false), {
|
||||
template: 'ListView.row.form',
|
||||
registry: openerp.base.list.form.widgets
|
||||
});
|
||||
|
@ -214,6 +208,9 @@ openerp.base.list.editable = function (openerp) {
|
|||
save_row: function (edit_next) {
|
||||
var self = this;
|
||||
this.edition_form.do_save(function (result) {
|
||||
if (result.created && !self.edition_index) {
|
||||
self.edition_index = self.dataset.index;
|
||||
}
|
||||
self.cancel_pending_edition().then(function () {
|
||||
$(self).trigger('saved', [self.dataset]);
|
||||
if (!edit_next) {
|
||||
|
@ -277,12 +274,13 @@ openerp.base.list.editable = function (openerp) {
|
|||
openerp.base.list.form[key] = (form_widgets.get_object(key)).extend({
|
||||
update_dom: function () {
|
||||
this.$element.children().css('visibility', '');
|
||||
if (this.invisible) {
|
||||
this.$element.children().css('visibility', 'hidden');
|
||||
} else {
|
||||
if (this.modifiers.tree_invisible) {
|
||||
var old_invisible = this.invisible;
|
||||
this.invisible = !!this.modifiers.tree_invisible;
|
||||
this._super();
|
||||
this.invisible = false;
|
||||
this.invisible = old_invisible;
|
||||
} else if (this.invisible) {
|
||||
this.$element.children().css('visibility', 'hidden');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,63 +1,5 @@
|
|||
openerp.base.list = function (openerp) {
|
||||
openerp.base.views.add('list', 'openerp.base.ListView');
|
||||
openerp.base.list = {
|
||||
/**
|
||||
* Formats the rendring of a given value based on its field type
|
||||
*
|
||||
* @param {Object} row_data record whose values should be displayed in the cell
|
||||
* @param {Object} column column descriptor
|
||||
* @param {"button"|"field"} column.tag base control type
|
||||
* @param {String} column.type widget type for a field control
|
||||
* @param {String} [column.string] button label
|
||||
* @param {String} [column.icon] button icon
|
||||
* @param {String} [value_if_empty=''] what to display if the field's value is ``false``
|
||||
*/
|
||||
render_cell: function (row_data, column, value_if_empty) {
|
||||
var attrs = column.modifiers_for(row_data);
|
||||
if (attrs.invisible) { return ''; }
|
||||
if (column.tag === 'button') {
|
||||
return [
|
||||
'<button type="button" title="', column.string || '', '">',
|
||||
'<img src="/base/static/src/img/icons/', column.icon, '.png"',
|
||||
' alt="', column.string || '', '"/>',
|
||||
'</button>'
|
||||
].join('')
|
||||
}
|
||||
|
||||
var value = row_data[column.id].value;
|
||||
|
||||
// If NaN value, display as with a `false` (empty cell)
|
||||
if (typeof value === 'number' && isNaN(value)) {
|
||||
value = false;
|
||||
}
|
||||
switch (value) {
|
||||
case false:
|
||||
case Infinity:
|
||||
case -Infinity:
|
||||
return value_if_empty === undefined ? '' : value_if_empty;
|
||||
}
|
||||
switch (column.widget || column.type) {
|
||||
case 'integer':
|
||||
return _.sprintf('%d', value);
|
||||
case 'float':
|
||||
var precision = column.digits ? column.digits[1] : 2;
|
||||
return _.sprintf('%.' + precision + 'f', value);
|
||||
case 'float_time':
|
||||
return _.sprintf("%02d:%02d",
|
||||
Math.floor(value),
|
||||
Math.round((value % 1) * 60));
|
||||
case 'progressbar':
|
||||
return _.sprintf(
|
||||
'<progress value="%.2f" max="100.0">%.2f%%</progress>',
|
||||
value, value);
|
||||
case 'many2one':
|
||||
// name_get value format
|
||||
return value[1];
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
};
|
||||
openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListView# */ {
|
||||
defaults: {
|
||||
// records can be selected one by one
|
||||
|
@ -85,8 +27,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
* the default behaviors and possible options for the list view.
|
||||
*
|
||||
* @constructs
|
||||
* @param view_manager
|
||||
* @param session An OpenERP session object
|
||||
* @param parent parent object
|
||||
* @param element_id the id of the DOM elements this view should link itself to
|
||||
* @param {openerp.base.DataSet} dataset the dataset the view should work with
|
||||
* @param {String} view_id the listview's identifier, if any
|
||||
|
@ -102,16 +43,13 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
*/
|
||||
init: function(parent, element_id, dataset, view_id, options) {
|
||||
this._super(parent, element_id);
|
||||
this.set_default_options();
|
||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
||||
this.set_default_options(_.extend({}, this.defaults, options || {}));
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
|
||||
this.columns = [];
|
||||
|
||||
this.options = _.extend({}, this.defaults, options || {});
|
||||
|
||||
this.set_groups(new openerp.base.ListView.Groups(this));
|
||||
|
||||
if (this.dataset instanceof openerp.base.DataSetStatic) {
|
||||
|
@ -123,7 +61,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
/**
|
||||
* Retrieves the view's number of records per page (|| section)
|
||||
*
|
||||
* options > defaults > view_manager.action.limit > indefinite
|
||||
* options > defaults > parent.action.limit > indefinite
|
||||
*
|
||||
* @returns {Number|null}
|
||||
*/
|
||||
|
@ -131,7 +69,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
if (this._limit === undefined) {
|
||||
this._limit = (this.options.limit
|
||||
|| this.defaults.limit
|
||||
|| (this.view_manager.action || {}).limit
|
||||
|| (this.widget_parent.action || {}).limit
|
||||
|| null);
|
||||
}
|
||||
return this._limit;
|
||||
|
@ -157,7 +95,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
self.do_delete(ids);
|
||||
},
|
||||
'action': function (e, action_name, id, callback) {
|
||||
self.do_action(action_name, id, callback);
|
||||
self.do_button_action(action_name, id, callback);
|
||||
},
|
||||
'row_link': function (e, id, dataset) {
|
||||
self.do_activate_record(dataset.index, id, dataset);
|
||||
|
@ -267,7 +205,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
})
|
||||
.val(self._limit || 'NaN');
|
||||
});
|
||||
if (this.options.sidebar && this.options.sidebar_id) {
|
||||
if (!this.sidebar && this.options.sidebar && this.options.sidebar_id) {
|
||||
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
||||
this.sidebar.start();
|
||||
this.sidebar.add_toolbar(data.fields_view.toolbar);
|
||||
|
@ -389,9 +327,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
view = view || 'form';
|
||||
this.dataset.index = index;
|
||||
_.delay(_.bind(function () {
|
||||
if(this.view_manager) {
|
||||
this.view_manager.on_mode_switch(view);
|
||||
}
|
||||
this.do_switch_view(view);
|
||||
}, this));
|
||||
},
|
||||
do_show: function () {
|
||||
|
@ -416,8 +352,9 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
* Reloads the list view based on the current settings (dataset & al)
|
||||
*
|
||||
* @param {Boolean} [grouped] Should the list be displayed grouped
|
||||
* @param {Object} [context] context to send the server while loading the view
|
||||
*/
|
||||
reload_view: function (grouped) {
|
||||
reload_view: function (grouped, context) {
|
||||
var self = this;
|
||||
var callback = function (field_view_get) {
|
||||
self.on_loaded(field_view_get, grouped);
|
||||
|
@ -428,7 +365,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
return this.rpc('/base/listview/load', {
|
||||
model: this.model,
|
||||
view_id: this.view_id,
|
||||
context: this.dataset.get_context(),
|
||||
context: this.dataset.get_context(context),
|
||||
toolbar: this.options.sidebar
|
||||
}, callback);
|
||||
}
|
||||
|
@ -464,11 +401,10 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
* @param {Object} results results of evaluating domain and process for a search
|
||||
*/
|
||||
do_actual_search: function (results) {
|
||||
this.dataset.context = results.context;
|
||||
this.dataset.domain = results.domain;
|
||||
this.groups.datagroup = new openerp.base.DataGroup(
|
||||
this, this.model,
|
||||
results.domain, results.context,
|
||||
this.dataset.get_domain(results.domain),
|
||||
this.dataset.get_context(results.context),
|
||||
results.group_by);
|
||||
this.groups.datagroup.sort = this.dataset._sort;
|
||||
|
||||
|
@ -476,7 +412,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
results.group_by = null;
|
||||
}
|
||||
|
||||
this.reload_view(!!results.group_by).then(
|
||||
this.reload_view(!!results.group_by, results.context).then(
|
||||
$.proxy(this, 'reload_content'));
|
||||
},
|
||||
/**
|
||||
|
@ -519,17 +455,16 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
* @param {Object} id id of the record the action should be called on
|
||||
* @param {Function} callback should be called after the action is executed, if non-null
|
||||
*/
|
||||
do_action: function (name, id, callback) {
|
||||
do_button_action: function (name, id, callback) {
|
||||
var self = this,
|
||||
action = _.detect(this.columns, function (field) {
|
||||
return field.name === name;
|
||||
});
|
||||
if (!action) { return; }
|
||||
this.execute_action(
|
||||
action, this.dataset, this.session.action_manager, id, function () {
|
||||
$.when(callback.apply(this, arguments).then(function () {
|
||||
self.compute_aggregates();
|
||||
}));
|
||||
this.execute_action(action, this.dataset, id, function () {
|
||||
$.when(callback.apply(this, arguments).then(function () {
|
||||
self.compute_aggregates();
|
||||
}));
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -541,11 +476,11 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
*/
|
||||
do_activate_record: function (index, id, dataset) {
|
||||
var self = this;
|
||||
_.extend(this.dataset, {
|
||||
domain: dataset.domain,
|
||||
context: dataset.get_context()
|
||||
}).read_slice([], 0, false, function () {
|
||||
self.select_record(index);
|
||||
this.dataset.read_slice({
|
||||
context: dataset.get_context(),
|
||||
domain: dataset.get_domain()
|
||||
}, function () {
|
||||
self.select_record(index);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -644,7 +579,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
|||
}
|
||||
|
||||
$footer_cells.filter(_.sprintf('[data-field=%s]', column.id))
|
||||
.html(openerp.base.list.render_cell(aggregation, column));
|
||||
.html(openerp.base.format_cell(aggregation, column));
|
||||
});
|
||||
}
|
||||
// TODO: implement reorder (drag and drop rows)
|
||||
|
@ -681,6 +616,7 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
|
|||
var self = this;
|
||||
this.group = group;
|
||||
this.view = group.view;
|
||||
this.session = this.view.session;
|
||||
|
||||
this.options = opts.options;
|
||||
this.columns = opts.columns;
|
||||
|
@ -731,7 +667,7 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
|
|||
this.$current = this.$_element.clone(true);
|
||||
this.$current.empty().append(
|
||||
QWeb.render('ListView.rows', _.extend({
|
||||
render_cell: openerp.base.list.render_cell}, this)));
|
||||
render_cell: openerp.base.format_cell}, this)));
|
||||
},
|
||||
/**
|
||||
* Gets the ids of all currently selected records, if any
|
||||
|
@ -862,7 +798,7 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
|
|||
row: this.rows[record_index],
|
||||
row_parity: (record_index % 2 === 0) ? 'even' : 'odd',
|
||||
row_index: record_index,
|
||||
render_cell: openerp.base.list.render_cell
|
||||
render_cell: openerp.base.format_cell
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -1022,7 +958,7 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
|
|||
row_data[group.grouped_on] = group;
|
||||
var group_column = _(self.columns).detect(function (column) {
|
||||
return column.id === group.grouped_on; });
|
||||
$group_column.html(openerp.base.list.render_cell(
|
||||
$group_column.html(openerp.base.format_cell(
|
||||
row_data, group_column, "Undefined"
|
||||
));
|
||||
if (group.openable) {
|
||||
|
@ -1098,10 +1034,11 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
|
|||
d = new $.Deferred(),
|
||||
page = this.datagroup.openable ? this.page : view.page;
|
||||
|
||||
dataset.read_slice(
|
||||
_.filter(_.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name'), _.identity),
|
||||
page * limit, limit,
|
||||
function (records) {
|
||||
dataset.read_slice({
|
||||
fields: _.filter(_.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name'), _.identity),
|
||||
offset: page * limit,
|
||||
limit: limit
|
||||
}, function (records) {
|
||||
if (!self.datagroup.openable) {
|
||||
view.configure_pager(dataset);
|
||||
} else {
|
||||
|
@ -1156,12 +1093,14 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
|
|||
// if drag to 1st row (to = 0), start sequencing from 0
|
||||
// (exclusive lower bound)
|
||||
seq = to ? list.rows[to - 1].data.sequence.value : 0;
|
||||
while (++seq, data = list.rows[index++].data) {
|
||||
while (++seq, list.rows[index]) {
|
||||
data = list.rows[index].data;
|
||||
data.sequence.value = seq;
|
||||
// write are independent from one another, so we can just
|
||||
// launch them all at the same time and we don't really
|
||||
// give a fig about when they're done
|
||||
dataset.write(data.id.value, {sequence: seq});
|
||||
list.reload_record(index++);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ openerp.base.search = function(openerp) {
|
|||
openerp.base.SearchView = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id, dataset, view_id, defaults) {
|
||||
this._super(parent, element_id);
|
||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
|
@ -140,7 +139,7 @@ openerp.base.SearchView = openerp.base.Widget.extend({
|
|||
var widget_starts = _(lines).chain().flatten().map(function (widget) {
|
||||
return widget.start();
|
||||
}).value();
|
||||
|
||||
|
||||
$.when.apply(null, widget_starts).then(function () {
|
||||
self.ready.resolve();
|
||||
});
|
||||
|
@ -203,10 +202,10 @@ openerp.base.SearchView = openerp.base.Widget.extend({
|
|||
context_to_save: context,
|
||||
domain: domain,
|
||||
name: name
|
||||
}).then(function(result) {
|
||||
}).then(function() {
|
||||
self.reload_managed_filters();
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
} else { // manage_filters
|
||||
|
@ -362,7 +361,6 @@ openerp.base.search.fields = new openerp.base.Registry({
|
|||
'selection': 'openerp.base.search.SelectionField',
|
||||
'datetime': 'openerp.base.search.DateTimeField',
|
||||
'date': 'openerp.base.search.DateField',
|
||||
'one2many': 'openerp.base.search.OneToManyField',
|
||||
'many2one': 'openerp.base.search.ManyToOneField',
|
||||
'many2many': 'openerp.base.search.ManyToManyField'
|
||||
});
|
||||
|
@ -475,11 +473,11 @@ openerp.base.search.Group = openerp.base.search.Widget.extend({
|
|||
},
|
||||
start: function () {
|
||||
this._super();
|
||||
_(this.lines)
|
||||
.chain()
|
||||
.flatten()
|
||||
.each(function (widget) { widget.start(); });
|
||||
openerp.base.search.add_expand_listener(this.$element);
|
||||
var widget_starts = _(this.lines).chain().flatten()
|
||||
.map(function (widget) { return widget.start(); })
|
||||
.value();
|
||||
return $.when.apply(null, widget_starts);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -624,39 +622,6 @@ openerp.base.search.CharField = openerp.base.search.Field.extend( /** @lends ope
|
|||
return this.$element.val();
|
||||
}
|
||||
});
|
||||
openerp.base.search.BooleanField = openerp.base.search.Field.extend({
|
||||
template: 'SearchView.field.selection',
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.attrs.selection = [
|
||||
['true', 'Yes'],
|
||||
['false', 'No']
|
||||
];
|
||||
},
|
||||
/**
|
||||
* Search defaults likely to be boolean values (for a boolean field).
|
||||
*
|
||||
* In the HTML, we only get strings, and our strings here are
|
||||
* <code>'true'</code> and <code>'false'</code>, so ensure we get only
|
||||
* those by truth-testing the default value.
|
||||
*
|
||||
* @param {Object} defaults default values for this search view
|
||||
*/
|
||||
render: function (defaults) {
|
||||
var name = this.attrs.name;
|
||||
if (name in defaults) {
|
||||
defaults[name] = defaults[name] ? "true" : "false";
|
||||
}
|
||||
return this._super(defaults);
|
||||
},
|
||||
get_value: function () {
|
||||
switch (this.$element.val()) {
|
||||
case 'false': return false;
|
||||
case 'true': return true;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
openerp.base.search.NumberField = openerp.base.search.Field.extend(/** @lends openerp.base.search.NumberField# */{
|
||||
get_value: function () {
|
||||
if (!this.$element.val()) {
|
||||
|
@ -693,93 +658,76 @@ openerp.base.search.FloatField = openerp.base.search.NumberField.extend(/** @len
|
|||
return parseFloat(value);
|
||||
}
|
||||
});
|
||||
openerp.base.search.SelectionField = openerp.base.search.Field.extend({
|
||||
/**
|
||||
* @class
|
||||
* @extends openerp.base.search.Field
|
||||
*/
|
||||
openerp.base.search.SelectionField = openerp.base.search.Field.extend(/** @lends openerp.base.search.SelectionField# */{
|
||||
template: 'SearchView.field.selection',
|
||||
get_value: function () {
|
||||
return this.$element.val();
|
||||
}
|
||||
});
|
||||
openerp.base.search.BooleanField = openerp.base.search.SelectionField.extend(/** @lends openerp.base.search.BooleanField# */{
|
||||
/**
|
||||
* @constructs
|
||||
* @extends openerp.base.search.BooleanField
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.attrs.selection = [
|
||||
['true', 'Yes'],
|
||||
['false', 'No']
|
||||
];
|
||||
},
|
||||
/**
|
||||
* Search defaults likely to be boolean values (for a boolean field).
|
||||
*
|
||||
* In the HTML, we only want/get strings, and our strings here are ``true``
|
||||
* and ``false``, so ensure we use precisely those by truth-testing the
|
||||
* default value (iif there is one in the view's defaults).
|
||||
*
|
||||
* @param {Object} defaults default values for this search view
|
||||
* @returns {String} rendered boolean field
|
||||
*/
|
||||
render: function (defaults) {
|
||||
var name = this.attrs.name;
|
||||
if (name in defaults) {
|
||||
defaults[name] = defaults[name] ? "true" : "false";
|
||||
}
|
||||
return this._super(defaults);
|
||||
},
|
||||
get_value: function () {
|
||||
switch (this.$element.val()) {
|
||||
case 'false': return false;
|
||||
case 'true': return true;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
openerp.base.search.DateField = openerp.base.search.Field.extend( /** @lends openerp.base.search.DateField# */{
|
||||
template: 'SearchView.fields.date',
|
||||
/**
|
||||
* enables date picker on the HTML widgets
|
||||
*/
|
||||
start: function () {
|
||||
this._super();
|
||||
this.$element.find('input').datepicker({
|
||||
this.$element.addClass('field_date').datepicker({
|
||||
dateFormat: 'yy-mm-dd'
|
||||
});
|
||||
},
|
||||
stop: function () {
|
||||
this.$element.find('input').datepicker('destroy');
|
||||
this.$element.datepicker('destroy');
|
||||
},
|
||||
/**
|
||||
* Returns an object with two optional keys ``from`` and ``to`` providing
|
||||
* the values for resp. the from and to sections of the date widget.
|
||||
*
|
||||
* If a key is absent, then the corresponding field was not filled.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
get_values: function () {
|
||||
var values_array = this.$element.find('input').serializeArray();
|
||||
|
||||
if (!values_array || !values_array[0]) {
|
||||
throw new openerp.base.search.Invalid(
|
||||
this.attrs.name, null, "widget not ready");
|
||||
}
|
||||
var from = values_array[0].value,
|
||||
to = values_array[1].value;
|
||||
|
||||
var field_values = {};
|
||||
if (from) {
|
||||
field_values.from = from;
|
||||
}
|
||||
if (to) {
|
||||
field_values.to = to;
|
||||
}
|
||||
return field_values;
|
||||
},
|
||||
get_context: function () {
|
||||
var values = this.get_values();
|
||||
if (!this.attrs.context || _.isEmpty(values)) {
|
||||
return null;
|
||||
}
|
||||
return _.extend(
|
||||
{}, this.attrs.context,
|
||||
{own_values: {self: values}});
|
||||
},
|
||||
get_domain: function () {
|
||||
var values = this.get_values();
|
||||
if (_.isEmpty(values)) {
|
||||
return null;
|
||||
}
|
||||
var domain = this.attrs['filter_domain'];
|
||||
if (!domain) {
|
||||
domain = [];
|
||||
if (values.from) {
|
||||
domain.push([this.attrs.name, '>=', values.from]);
|
||||
}
|
||||
if (values.to) {
|
||||
domain.push([this.attrs.name, '<=', values.to]);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
return _.extend(
|
||||
{}, domain,
|
||||
{own_values: {self: values}});
|
||||
get_value: function () {
|
||||
return this.$element.val();
|
||||
}
|
||||
});
|
||||
openerp.base.search.DateTimeField = openerp.base.search.DateField.extend({
|
||||
// TODO: time?
|
||||
});
|
||||
openerp.base.search.OneToManyField = openerp.base.search.CharField.extend({
|
||||
// TODO: .relation, .context, .domain
|
||||
});
|
||||
openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({
|
||||
// TODO: @widget
|
||||
// TODO: .relation, .selection, .context, .domain
|
||||
// TODO: .selection, .context, .domain
|
||||
init: function (view_section, field, view) {
|
||||
this._super(view_section, field, view);
|
||||
var self = this;
|
||||
|
@ -847,9 +795,12 @@ openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({
|
|||
return this._super();
|
||||
}
|
||||
});
|
||||
openerp.base.search.ManyToManyField = openerp.base.search.CharField.extend({
|
||||
// TODO: .related_columns (Array), .context, .domain
|
||||
});
|
||||
/**
|
||||
* m2m search field behaves pretty much exactly like a char field
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
openerp.base.search.ManyToManyField = openerp.base.search.CharField.extend({});
|
||||
|
||||
openerp.base.search.ExtendedSearch = openerp.base.OldWidget.extend({
|
||||
template: 'SearchView.extended_search',
|
||||
|
|
|
@ -5,22 +5,202 @@
|
|||
openerp.base.view_tree = function(openerp) {
|
||||
|
||||
openerp.base.views.add('tree', 'openerp.base.TreeView');
|
||||
openerp.base.TreeView = openerp.base.Widget.extend({
|
||||
/**
|
||||
* Genuine tree view (the one displayed as a tree, not the list)
|
||||
*/
|
||||
openerp.base.TreeView = openerp.base.View.extend({
|
||||
/**
|
||||
* Indicates that this view is not searchable, and thus that no search
|
||||
* view should be displayed (if there is one active).
|
||||
*/
|
||||
searchable : false,
|
||||
|
||||
init: function(parent, element_id, dataset, view_id, options) {
|
||||
this._super(parent, element_id);
|
||||
this.dataset = dataset;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
|
||||
this.records = {};
|
||||
|
||||
this.options = _.extend({}, this.defaults, options || {});
|
||||
},
|
||||
|
||||
start: function () {
|
||||
this._super();
|
||||
this.$element.append('Tree view');
|
||||
return this.rpc("/base/treeview/load", {
|
||||
model: this.model,
|
||||
view_id: this.view_id,
|
||||
toolbar: this.view_manager ? !!this.view_manager.sidebar : false
|
||||
}, this.on_loaded);
|
||||
},
|
||||
/**
|
||||
* Returns the list of fields needed to correctly read objects.
|
||||
*
|
||||
* Gathers the names of all fields in fields_view_get, and adds the
|
||||
* field_parent (children_field in the tree view) if it's not already one
|
||||
* of the fields to fetch
|
||||
*
|
||||
* @returns {Array} an array of fields which can be provided to DataSet.read_slice and others
|
||||
*/
|
||||
fields_list: function () {
|
||||
var fields = _.keys(this.fields);
|
||||
if (!_(fields).contains(this.children_field)) {
|
||||
fields.push(this.children_field);
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
on_loaded: function (fields_view) {
|
||||
var self = this;
|
||||
var has_toolbar = !!fields_view.arch.attrs.toolbar;
|
||||
// field name in OpenERP is kinda stupid: this is the name of the field
|
||||
// holding the ids to the children of the current node, why call it
|
||||
// field_parent?
|
||||
this.children_field = fields_view['field_parent'];
|
||||
this.fields_view = fields_view;
|
||||
_(this.fields_view.arch.children).each(function (field) {
|
||||
if (field.attrs.modifiers) {
|
||||
field.attrs.modifiers = JSON.parse(field.attrs.modifiers);
|
||||
}
|
||||
});
|
||||
this.fields = fields_view.fields;
|
||||
this.hook_row_click();
|
||||
this.$element.html(QWeb.render('TreeView', {
|
||||
'title': this.fields_view.arch.attrs.string,
|
||||
'fields_view': this.fields_view.arch.children,
|
||||
'fields': this.fields,
|
||||
'toolbar': has_toolbar
|
||||
}));
|
||||
|
||||
this.dataset.read_slice({fields: this.fields_list()}, function (records) {
|
||||
if (!has_toolbar) {
|
||||
// WARNING: will do a second read on the same ids, but only on
|
||||
// first load so not very important
|
||||
self.getdata(null, _(records).pluck('id'));
|
||||
return;
|
||||
}
|
||||
|
||||
var $select = self.$element.find('select')
|
||||
.change(function () {
|
||||
var $option = $(this).find(':selected');
|
||||
self.getdata($option.val(), $option.data('children'));
|
||||
});
|
||||
_(records).each(function (record) {
|
||||
self.records[record.id] = record;
|
||||
$('<option>')
|
||||
.val(record.id)
|
||||
.text(record.name)
|
||||
.data('children', record[self.children_field])
|
||||
.appendTo($select);
|
||||
});
|
||||
|
||||
if (!_.isEmpty(records)) {
|
||||
$select.change();
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Sets up opening a row
|
||||
*/
|
||||
hook_row_click: function () {
|
||||
var self = this;
|
||||
this.$element.delegate('.treeview-td span, .treeview-tr span', 'click', function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
self.activate($(this).closest('tr').data('id'));
|
||||
});
|
||||
|
||||
this.$element.delegate('.treeview-tr', 'click', function () {
|
||||
var is_loaded = 0,
|
||||
$this = $(this),
|
||||
record_id = $this.data('id'),
|
||||
record = self.records[record_id],
|
||||
children_ids = record[self.children_field];
|
||||
|
||||
_(children_ids).each(function(childid) {
|
||||
if (self.$element.find('#treerow_' + childid).length) {
|
||||
if (self.$element.find('#treerow_' + childid).is(':hidden')) {
|
||||
is_loaded = -1;
|
||||
} else {
|
||||
is_loaded++;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (is_loaded === 0) {
|
||||
if (!$this.parent().hasClass('oe-open')) {
|
||||
self.getdata(record_id, children_ids);
|
||||
}
|
||||
} else {
|
||||
self.showcontent(record_id, is_loaded < 0);
|
||||
}
|
||||
});
|
||||
},
|
||||
// get child data of selected value
|
||||
getdata: function (id, children_ids) {
|
||||
var self = this;
|
||||
|
||||
self.dataset.read_ids(children_ids, this.fields_list(), function (records) {
|
||||
_(records).each(function (record) {
|
||||
self.records[record.id] = record;
|
||||
});
|
||||
|
||||
var $curr_node = self.$element.find('#treerow_' + id);
|
||||
var children_rows = QWeb.render('TreeView.rows', {
|
||||
'records': records,
|
||||
'children_field': self.children_field,
|
||||
'fields_view': self.fields_view.arch.children,
|
||||
'fields': self.fields,
|
||||
'level': $curr_node.data('level') || 0,
|
||||
'render': openerp.base.format_value
|
||||
});
|
||||
|
||||
if ($curr_node.length) {
|
||||
$curr_node.addClass('oe-open');
|
||||
$curr_node.after(children_rows);
|
||||
} else {
|
||||
self.$element.find('tbody').html(children_rows);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Get details in listview
|
||||
activate: function(id) {
|
||||
var self = this;
|
||||
this.rpc('/base/treeview/action', {
|
||||
id: id,
|
||||
model: this.dataset.model,
|
||||
context: new openerp.base.CompoundContext(
|
||||
this.dataset.get_context(), {
|
||||
active_model: this.dataset.model,
|
||||
active_id: id,
|
||||
active_ids: [id]})
|
||||
}, function (actions) {
|
||||
if (!actions.length) { return; }
|
||||
var action = actions[0][2];
|
||||
self.do_action(action);
|
||||
});
|
||||
},
|
||||
|
||||
// show & hide the contents
|
||||
showcontent: function (record_id, show) {
|
||||
this.$element.find('#treerow_' + record_id)
|
||||
.toggleClass('oe-open', show);
|
||||
|
||||
_(this.records[record_id][this.children_field]).each(function (child_id) {
|
||||
var $child_row = this.$element.find('#treerow_' + child_id);
|
||||
if ($child_row.hasClass('oe-open')) {
|
||||
this.showcontent(child_id, false);
|
||||
}
|
||||
$child_row.toggle(show);
|
||||
}, this);
|
||||
},
|
||||
|
||||
do_show: function () {
|
||||
this.$element.show();
|
||||
},
|
||||
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
this.hidden = true;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
|
|
@ -4,127 +4,113 @@
|
|||
|
||||
openerp.base.views = function(openerp) {
|
||||
|
||||
openerp.base.ActionManager = openerp.base.Widget.extend({
|
||||
// process all kind of actions
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
this.viewmanager = null;
|
||||
this.current_dialog = null;
|
||||
// Temporary linking view_manager to session.
|
||||
// Will use parent to find it when implementation will be done.
|
||||
this.session.action_manager = this;
|
||||
},
|
||||
/**
|
||||
* Process an action
|
||||
* Supported actions: act_window
|
||||
*/
|
||||
action_window: function() {
|
||||
},
|
||||
action_window_close: function() {
|
||||
},
|
||||
action_server: function() {
|
||||
},
|
||||
action_url: function() {
|
||||
},
|
||||
action_report: function() {
|
||||
},
|
||||
action_client: function() {
|
||||
},
|
||||
do_action: function(action, on_closed) {
|
||||
var self = this;
|
||||
action.flags = _.extend({
|
||||
sidebar : action.target != 'new',
|
||||
search_view : action.target != 'new',
|
||||
new_window : false,
|
||||
views_switcher : action.target != 'new',
|
||||
action_buttons : action.target != 'new',
|
||||
pager : action.target != 'new'
|
||||
}, action.flags || {});
|
||||
// instantiate the right controllers by understanding the action
|
||||
switch (action.type) {
|
||||
case 'ir.actions.act_window':
|
||||
if (!action.target && this.current_dialog) {
|
||||
action.flags.new_window = true;
|
||||
}
|
||||
if (action.target == 'new') {
|
||||
var dialog = this.current_dialog = new openerp.base.ActionDialog(this, { title: action.name, width: '90%' });
|
||||
if (on_closed) {
|
||||
dialog.close_callback = on_closed;
|
||||
}
|
||||
dialog.start(false);
|
||||
var viewmanager = dialog.viewmanager = new openerp.base.ViewManagerAction(this, dialog.element_id, action);
|
||||
viewmanager.start();
|
||||
dialog.open();
|
||||
} else if (action.flags.new_window) {
|
||||
action.flags.new_window = false;
|
||||
this.rpc("/base/session/save_session_action", { the_action : action}, function(key) {
|
||||
var url = window.location.protocol + "//" + window.location.host +
|
||||
window.location.pathname + "?" + jQuery.param({ s_action : "" + key });
|
||||
window.open(url);
|
||||
if (on_closed) {
|
||||
on_closed();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.viewmanager) {
|
||||
this.viewmanager.stop();
|
||||
}
|
||||
this.viewmanager = new openerp.base.ViewManagerAction(this, this.element_id, action);
|
||||
this.viewmanager.start();
|
||||
}
|
||||
break;
|
||||
case 'ir.actions.act_window_close':
|
||||
this.close_dialog();
|
||||
break;
|
||||
case 'ir.actions.server':
|
||||
this.rpc('/base/action/run', {
|
||||
action_id: action.id,
|
||||
context: {active_id: 66, active_ids: [66], active_model: 'ir.ui.menu'}
|
||||
}).then(function (action) {
|
||||
self.do_action(action, on_closed)
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log("Action manager can't handle action of type " + action.type, action);
|
||||
}
|
||||
},
|
||||
close_dialog: function() {
|
||||
if (this.current_dialog) {
|
||||
this.current_dialog.stop();
|
||||
this.current_dialog = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Registry for all the client actions key: tag value: widget
|
||||
*/
|
||||
openerp.base.client_actions = new openerp.base.Registry();
|
||||
|
||||
openerp.base.ActionDialog = openerp.base.Dialog.extend({
|
||||
identifier_prefix: 'action_dialog',
|
||||
on_close: function() {
|
||||
this._super(this, arguments);
|
||||
if (this.close_callback) {
|
||||
this.close_callback();
|
||||
openerp.base.ActionManager = openerp.base.Widget.extend({
|
||||
identifier_prefix: "actionmanager",
|
||||
init: function(parent) {
|
||||
this._super(parent);
|
||||
this.inner_viewmanager = null;
|
||||
this.dialog = null;
|
||||
this.dialog_viewmanager = null;
|
||||
this.client_widget = null;
|
||||
},
|
||||
render: function() {
|
||||
return "<div id='"+this.element_id+"'></div>";
|
||||
},
|
||||
dialog_stop: function () {
|
||||
if (this.dialog) {
|
||||
this.dialog_viewmanager.stop();
|
||||
this.dialog_viewmanager = null;
|
||||
this.dialog.stop();
|
||||
this.dialog = null;
|
||||
}
|
||||
},
|
||||
stop: function() {
|
||||
this._super(this, arguments);
|
||||
if (this.viewmanager) {
|
||||
this.viewmanager.stop();
|
||||
inner_stop: function () {
|
||||
if (this.inner_viewmanager) {
|
||||
this.inner_viewmanager.stop();
|
||||
this.inner_viewmanager = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
do_action: function(action, on_close) {
|
||||
var type = action.type.replace(/\./g,'_');
|
||||
var popup = action.target === 'new';
|
||||
action.flags = _.extend({
|
||||
views_switcher : !popup,
|
||||
search_view : !popup,
|
||||
action_buttons : !popup,
|
||||
sidebar : !popup,
|
||||
pager : !popup
|
||||
}, action.flags || {});
|
||||
if (!(type in this)) {
|
||||
this.log("Action manager can't handle action of type " + action.type, action);
|
||||
return;
|
||||
}
|
||||
this[type](action, on_close);
|
||||
},
|
||||
ir_actions_act_window: function (action, on_close) {
|
||||
if (action.target === 'new') {
|
||||
if (this.dialog == null) {
|
||||
this.dialog = new openerp.base.Dialog(this, { title: action.name, width: '80%' });
|
||||
if(on_close)
|
||||
this.dialog.on_close.add(on_close);
|
||||
this.dialog.start();
|
||||
} else {
|
||||
this.dialog_viewmanager.stop();
|
||||
}
|
||||
this.dialog_viewmanager = new openerp.base.ViewManagerAction(this, action);
|
||||
this.dialog_viewmanager.appendTo(this.dialog.$element);
|
||||
this.dialog.open();
|
||||
} else {
|
||||
this.dialog_stop();
|
||||
this.inner_stop();
|
||||
this.inner_viewmanager = new openerp.base.ViewManagerAction(this, action);
|
||||
this.inner_viewmanager.appendTo(this.$element);
|
||||
}
|
||||
/* new window code
|
||||
this.rpc("/base/session/save_session_action", { the_action : action}, function(key) {
|
||||
var url = window.location.protocol + "//" + window.location.host + window.location.pathname + "?" + jQuery.param({ s_action : "" + key });
|
||||
window.open(url,'_blank');
|
||||
});
|
||||
*/
|
||||
},
|
||||
ir_actions_act_window_close: function (action, on_closed) {
|
||||
this.dialog_stop();
|
||||
},
|
||||
ir_actions_server: function (action, on_closed) {
|
||||
var self = this;
|
||||
this.rpc('/base/action/run', {
|
||||
action_id: action.id,
|
||||
context: {active_id: 66, active_ids: [66], active_model: 'ir.ui.menu'}
|
||||
}).then(function (action) {
|
||||
self.do_action(action, on_closed)
|
||||
});
|
||||
},
|
||||
ir_actions_client: function (action) {
|
||||
this.client_widget = openerp.base.client_actions.get_object(action.tag);
|
||||
new this.client_widget(this, this.element_id, action.params).start();
|
||||
},
|
||||
});
|
||||
|
||||
openerp.base.ViewManager = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id, dataset, views) {
|
||||
this._super(parent, element_id);
|
||||
identifier_prefix: "viewmanager",
|
||||
init: function(parent, dataset, views) {
|
||||
this._super(parent);
|
||||
this.model = dataset.model;
|
||||
this.dataset = dataset;
|
||||
this.searchview = null;
|
||||
this.active_view = null;
|
||||
this.views_src = _.map(views, function(x)
|
||||
{return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;});
|
||||
this.views_src = _.map(views, function(x) {return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;});
|
||||
this.views = {};
|
||||
this.flags = this.flags || {};
|
||||
this.registry = openerp.base.views;
|
||||
},
|
||||
render: function() {
|
||||
return QWeb.render("ViewManager", {"prefix": this.element_id, views: this.views_src})
|
||||
},
|
||||
/**
|
||||
* @returns {jQuery.Deferred} initial view loading promise
|
||||
*/
|
||||
|
@ -132,17 +118,20 @@ openerp.base.ViewManager = openerp.base.Widget.extend({
|
|||
this._super();
|
||||
var self = this;
|
||||
this.dataset.start();
|
||||
this.$element.html(QWeb.render("ViewManager", {"prefix": this.element_id, views: this.views_src}));
|
||||
this.$element.find('.oe_vm_switch button').click(function() {
|
||||
self.on_mode_switch($(this).data('view-type'));
|
||||
});
|
||||
var views_ids = {};
|
||||
_.each(this.views_src, function(view) {
|
||||
self.views[view.view_type] = $.extend({}, view, {
|
||||
controller : null,
|
||||
options : _.extend({
|
||||
sidebar_id : self.element_id + '_sidebar_' + view.view_type
|
||||
}, self.flags)
|
||||
sidebar_id : self.element_id + '_sidebar_' + view.view_type,
|
||||
action : self.action,
|
||||
action_views_ids : views_ids
|
||||
}, self.flags, view.options || {})
|
||||
});
|
||||
views_ids[view.view_type] = view.view_id;
|
||||
});
|
||||
if (this.flags.views_switcher === false) {
|
||||
this.$element.find('.oe_vm_switch').hide();
|
||||
|
@ -150,8 +139,6 @@ openerp.base.ViewManager = openerp.base.Widget.extend({
|
|||
// switch to the first one in sequence
|
||||
return this.on_mode_switch(this.views_src[0].view_type);
|
||||
},
|
||||
stop: function() {
|
||||
},
|
||||
/**
|
||||
* Asks the view manager to switch visualization mode.
|
||||
*
|
||||
|
@ -171,6 +158,7 @@ openerp.base.ViewManager = openerp.base.Widget.extend({
|
|||
if (view.embedded_view) {
|
||||
controller.set_embedded_view(view.embedded_view);
|
||||
}
|
||||
controller.do_switch_view.add_last(this.on_mode_switch);
|
||||
if (view_type === 'list' && this.flags.search_view === false && this.action && this.action['auto_search']) {
|
||||
// In case the search view is not instantiated: manually call ListView#search
|
||||
var domains = !_(self.action.domain).isEmpty()
|
||||
|
@ -220,11 +208,12 @@ openerp.base.ViewManager = openerp.base.Widget.extend({
|
|||
},
|
||||
/**
|
||||
* Event launched when a controller has been inited.
|
||||
*
|
||||
*
|
||||
* @param {String} view_type type of view
|
||||
* @param {String} view the inited controller
|
||||
*/
|
||||
on_controller_inited: function(view_type, view) {},
|
||||
on_controller_inited: function(view_type, view) {
|
||||
},
|
||||
/**
|
||||
* Sets up the current viewmanager's search view.
|
||||
*
|
||||
|
@ -241,9 +230,8 @@ openerp.base.ViewManager = openerp.base.Widget.extend({
|
|||
this.searchview.hide();
|
||||
}
|
||||
this.searchview.on_search.add(function(domains, contexts, groupbys) {
|
||||
self.views[self.active_view].controller.do_search.call(
|
||||
self, domains.concat(self.domains()),
|
||||
contexts.concat(self.contexts()), groupbys);
|
||||
var controller = self.views[self.active_view].controller;
|
||||
controller.do_search.call(controller, domains, contexts, groupbys);
|
||||
});
|
||||
return this.searchview.start();
|
||||
},
|
||||
|
@ -257,50 +245,22 @@ openerp.base.ViewManager = openerp.base.Widget.extend({
|
|||
on_remove: function() {
|
||||
},
|
||||
on_edit: function() {
|
||||
},
|
||||
/**
|
||||
* Domains added on searches by the view manager, to override in subsequent
|
||||
* view manager in order to add new pieces of domains to searches
|
||||
*
|
||||
* @returns an empty list
|
||||
*/
|
||||
domains: function () {
|
||||
return [];
|
||||
},
|
||||
/**
|
||||
* Contexts added on searches by the view manager.
|
||||
*
|
||||
* @returns an empty list
|
||||
*/
|
||||
contexts: function () {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.NullViewManager = openerp.base.generate_null_object_class(openerp.base.ViewManager, {
|
||||
init: function(parent) {
|
||||
this._super(parent);
|
||||
if(parent)
|
||||
this.session = parent.session;
|
||||
this.action = {flags: {}};
|
||||
}
|
||||
});
|
||||
|
||||
// TODO Will move to action Manager
|
||||
openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
||||
init: function(parent, element_id, action) {
|
||||
init: function(parent, action) {
|
||||
this.session = parent.session;
|
||||
this.action = action;
|
||||
var dataset;
|
||||
if (!action.res_id) {
|
||||
dataset = new openerp.base.DataSetSearch(this, action.res_model, action.context || null);
|
||||
dataset = new openerp.base.DataSetSearch(this, action.res_model, action.context, action.domain);
|
||||
} else {
|
||||
dataset = new openerp.base.DataSetStatic(this, action.res_model, {}, [action.res_id]);
|
||||
if (action.context) {
|
||||
// TODO fme: should normalize all DataSets constructors to (session, model, context, ...)
|
||||
dataset.context = action.context;
|
||||
}
|
||||
this.action.flags.search_view = false;
|
||||
dataset = new openerp.base.DataSetStatic(this, action.res_model, action.context, [action.res_id]);
|
||||
dataset.index = 0;
|
||||
}
|
||||
this._super(parent, element_id, dataset, action.views);
|
||||
this._super(parent, dataset, action.views);
|
||||
this.action = action;
|
||||
this.flags = this.action.flags || {};
|
||||
if (action.res_model == 'board.board' && action.views.length == 1 && action.views) {
|
||||
|
@ -332,32 +292,6 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
|||
.then(this.searchview.do_search);
|
||||
}
|
||||
}
|
||||
},
|
||||
stop: function() {
|
||||
// should be replaced by automatic destruction implemented in Widget
|
||||
this._super();
|
||||
},
|
||||
/**
|
||||
* adds action domain to the search domains
|
||||
*
|
||||
* @returns the action's domain
|
||||
*/
|
||||
domains: function () {
|
||||
if (!this.action.domain) {
|
||||
return [];
|
||||
}
|
||||
return [this.action.domain];
|
||||
},
|
||||
/**
|
||||
* adds action context to the search contexts
|
||||
*
|
||||
* @returns the action's context
|
||||
*/
|
||||
contexts: function () {
|
||||
if (!this.action.context) {
|
||||
return [];
|
||||
}
|
||||
return [this.action.context];
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -453,7 +387,9 @@ openerp.base.View = openerp.base.Widget.extend({
|
|||
_.defaults(this.options, {
|
||||
// All possible views options should be defaulted here
|
||||
sidebar_id: null,
|
||||
sidebar: true
|
||||
sidebar: true,
|
||||
action: null,
|
||||
action_views_ids: {}
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -465,17 +401,12 @@ openerp.base.View = openerp.base.Widget.extend({
|
|||
* @param {String} [action_data.type='workflow'] the action type, if present, one of ``'object'``, ``'action'`` or ``'workflow'``
|
||||
* @param {Object} [action_data.context=null] additional action context, to add to the current context
|
||||
* @param {openerp.base.DataSet} dataset a dataset object used to communicate with the server
|
||||
* @param {openerp.base.ActionManager} action_manager object able to actually execute the action, if any is fetched
|
||||
* @param {Object} [record_id] the identifier of the object on which the action is to be applied
|
||||
* @param {Function} on_closed callback to execute when dialog is closed or when the action does not generate any result (no new action)
|
||||
*/
|
||||
execute_action: function (action_data, dataset, action_manager, record_id, on_closed) {
|
||||
execute_action: function (action_data, dataset, record_id, on_closed) {
|
||||
var self = this;
|
||||
if (action_manager.current_dialog) {
|
||||
on_closed = action_manager.current_dialog.close_callback;
|
||||
}
|
||||
var handler = function (r) {
|
||||
action_manager.close_dialog();
|
||||
var action = r.result;
|
||||
if (action && action.constructor == Object) {
|
||||
action.context = action.context || {};
|
||||
|
@ -484,38 +415,36 @@ openerp.base.View = openerp.base.Widget.extend({
|
|||
active_ids: [record_id || false],
|
||||
active_model: dataset.model
|
||||
});
|
||||
action.flags = {
|
||||
new_window: true
|
||||
};
|
||||
action_manager.do_action(action, on_closed);
|
||||
self.do_action(action, on_closed);
|
||||
} else if (on_closed) {
|
||||
on_closed(action);
|
||||
}
|
||||
};
|
||||
|
||||
if (!action_data.special) {
|
||||
var context = new openerp.base.CompoundContext(dataset.get_context(), action_data.context || {});
|
||||
switch(action_data.type) {
|
||||
case 'object':
|
||||
return dataset.call_button(action_data.name, [[record_id], context], handler);
|
||||
case 'action':
|
||||
return this.rpc('/base/action/load', { action_id: parseInt(action_data.name, 10), context: context }, handler);
|
||||
default:
|
||||
return dataset.exec_workflow(record_id, action_data.name, handler);
|
||||
}
|
||||
} else {
|
||||
action_manager.close_dialog();
|
||||
}
|
||||
var context = new openerp.base.CompoundContext(dataset.get_context(), action_data.context || {});
|
||||
|
||||
if (action_data.special) {
|
||||
handler({result: {"type":"ir.actions.act_window_close"}});
|
||||
} else if (action_data.type=="object") {
|
||||
return dataset.call_button(action_data.name, [[record_id], context], handler);
|
||||
} else if (action_data.type=="action") {
|
||||
return this.rpc('/base/action/load', { action_id: parseInt(action_data.name, 10), context: context }, handler);
|
||||
} else {
|
||||
return dataset.exec_workflow(record_id, action_data.name, handler);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Directly set a view to use instead of calling fields_view_get. This method must
|
||||
* be called before start(). When an embedded view is set, underlying implementations
|
||||
* of openerp.base.View must use the provided view instead of any other one.
|
||||
*
|
||||
*
|
||||
* @param embedded_view A view.
|
||||
*/
|
||||
set_embedded_view: function(embedded_view) {
|
||||
this.embedded_view = embedded_view;
|
||||
this.options.sidebar = false;
|
||||
},
|
||||
do_switch_view: function(view) {
|
||||
},
|
||||
set_common_sidebar_sections: function(sidebar) {
|
||||
sidebar.add_section('customize', "Customize", [
|
||||
|
@ -553,19 +482,23 @@ openerp.base.View = openerp.base.Widget.extend({
|
|||
]);
|
||||
},
|
||||
on_sidebar_manage_view: function() {
|
||||
console.log('Todo');
|
||||
if (this.fields_view && this.fields_view.arch) {
|
||||
$('<xmp>' + openerp.base.json_node_to_xml(this.fields_view.arch, true) + '</xmp>').dialog({ width: '95%', height: 600});
|
||||
} else {
|
||||
this.notification.warn("Manage Views", "Could not find current view declaration");
|
||||
}
|
||||
},
|
||||
on_sidebar_edit_workflow: function() {
|
||||
console.log('Todo');
|
||||
this.log('Todo');
|
||||
},
|
||||
on_sidebar_customize_object: function() {
|
||||
console.log('Todo');
|
||||
this.log('Todo');
|
||||
},
|
||||
on_sidebar_import: function() {
|
||||
},
|
||||
on_sidebar_export: function() {
|
||||
var export_view = new openerp.base.DataExport(this, this.dataset);
|
||||
export_view.start(false);
|
||||
export_view.start();
|
||||
},
|
||||
on_sidebar_translate: function() {
|
||||
},
|
||||
|
|
|
@ -19,23 +19,30 @@
|
|||
</div>
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" class="main_table">
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<td colspan="2" valign="top">
|
||||
<div id="oe_header" class="header"></div>
|
||||
<div id="oe_menu" class="menu"></div>
|
||||
</td>
|
||||
</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 valign="top" >
|
||||
<div id="oe_app" class="oe-application">
|
||||
<div style="width:100%;">&nbsp;</div>
|
||||
</div>
|
||||
</tr>
|
||||
<tr class="db_options_row">
|
||||
<td valign="top" class="db_container">
|
||||
<div id="oe_database" class="database"></div>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<div id="oe_db_options"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" class="login-container" colspan="2">
|
||||
<div id="oe_login" class="login"></div>
|
||||
<td valign="top" id="oe_secondary_menu" class="secondary_menu">
|
||||
</td>
|
||||
<td valign="top">
|
||||
<div id="oe_app" class="oe-application">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -50,8 +57,190 @@
|
|||
<t t-name="Loading">
|
||||
Loading...
|
||||
</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" class="oe_forms" 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">Master 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"/></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">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" class="oe_forms" 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">Master 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" class="oe_forms" 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">Master 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" class="oe_forms" 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">Master 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" class="oe_forms" method="POST">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td class="option_string">
|
||||
CHANGE MASTER PASSWORD
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table align="center" class="db_option_table">
|
||||
<tr>
|
||||
<td><label for="old_pwd">Master 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 master password:</label></td>
|
||||
<td><input type="password" name="new_pwd" class="required"
|
||||
minlength="1"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="confirm_pwd">Confirm new master 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">
|
||||
<form>
|
||||
<form class="oe_forms">
|
||||
<fieldset>
|
||||
<legend style="">
|
||||
<img src="/base/static/src/img/stock_person.png" alt="" />
|
||||
|
@ -92,6 +281,7 @@
|
|||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button type="button" id="oe-db-config">Database</button>
|
||||
<button type="submit" name="submit">Login</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -258,6 +448,41 @@
|
|||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="TreeView">
|
||||
<h2 class="oe_view_title"><t t-esc="title"/></h2>
|
||||
<select t-if="toolbar" style="width: 30%">
|
||||
</select>
|
||||
<table class="oe-treeview-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th t-foreach="fields_view" t-as="field"
|
||||
t-if="!field.attrs.modifiers.tree_invisible"
|
||||
class="treeview-header">
|
||||
<t t-esc="fields[field.attrs.name].string" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
<tr t-name="TreeView.rows"
|
||||
t-foreach="records" t-as="record"
|
||||
t-att-id="'treerow_' + record.id"
|
||||
t-att-data-id="record.id" t-att-data-level="level + 1">
|
||||
<t t-set="children" t-value="record[children_field]"/>
|
||||
<t t-set="has_children" t-value="children and children.length"/>
|
||||
|
||||
<td t-foreach="fields_view" t-as="field"
|
||||
t-if="!field.attrs.modifiers.tree_invisible"
|
||||
t-att-data-id="record.id"
|
||||
t-att-style="!field_index ? 'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px' : undefined"
|
||||
t-att-class="!field_index and has_children ? 'treeview-tr' : 'treeview-td'">
|
||||
<span t-if="!field.attrs.modifiers.invisible">
|
||||
<t t-esc="render(record[field.attrs.name], fields[field.attrs.name])" />
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<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)"/>
|
||||
<thead class="ui-widget-header">
|
||||
|
@ -322,14 +547,9 @@
|
|||
</tfoot>
|
||||
</table>
|
||||
<t t-name="ListView.rows" t-foreach="rows" t-as="row">
|
||||
<t t-call="ListView.row">
|
||||
<t t-set="style" t-value="null"/>
|
||||
<t-if test="row.color">
|
||||
<t t-set="style" t-value="'color: ' + row.color"/>
|
||||
</t-if>
|
||||
</t>
|
||||
<t t-call="ListView.row"/>
|
||||
</t>
|
||||
<tr t-name="ListView.row" t-att-style="style" t-att-class="row_parity"
|
||||
<tr t-name="ListView.row" t-att-class="row_parity"
|
||||
t-att-data-index="row_index">
|
||||
<t t-foreach="columns" t-as="column">
|
||||
<td t-if="column.meta">
|
||||
|
@ -420,7 +640,7 @@
|
|||
<t t-raw="console.log('Unhandled widget', widget)"/>
|
||||
</t>
|
||||
<t t-name="WidgetFrame">
|
||||
<table border="0" width="100%" cellpadding="0" cellspacing="0" class="oe_frame">
|
||||
<table border="0" width="100%" cellpadding="0" cellspacing="0" class="oe_frame oe_forms">
|
||||
<tr t-foreach="widget.table" t-as="row">
|
||||
<t t-foreach="row" t-as="td">
|
||||
<td t-att-colspan="td.colspan gt 1 ? td.colspan : undefined"
|
||||
|
@ -461,8 +681,7 @@
|
|||
<t t-name="WidgetLabel">
|
||||
<label t-att-for="widget.element_id + '_field'"
|
||||
t-att-class="'oe_form_label' + (widget.help ? '_help' : '')"
|
||||
t-att-title="widget.help"
|
||||
t-att-ondblclick="'console.log(\'' + widget.element_id + '\', openerp.screen.' + widget.element_id + ')'">
|
||||
t-att-title="widget.help">
|
||||
<t t-esc="widget.string"/>
|
||||
<span t-if="widget.help">?</span>
|
||||
<t t-if="widget.string and widget.node.tag != 'label'">:</t>
|
||||
|
@ -678,7 +897,7 @@
|
|||
</t>
|
||||
<t t-name="SearchView">
|
||||
<h2 class="oe_view_title"><t t-esc="view.attrs['string']"/></h2>
|
||||
<form>
|
||||
<form class="oe_forms">
|
||||
<t t-call="SearchView.render_lines"/>
|
||||
<div class="oe_search-view-buttons" style="text-align: right;">
|
||||
<input type="submit" value="Search"/>
|
||||
|
@ -744,22 +963,6 @@
|
|||
<t t-if="filters.length" t-raw="filters.render(defaults)"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="SearchView.fields.date">
|
||||
<label style="display: block" t-att-title="attrs.help"
|
||||
t-att-for="element_id">
|
||||
<t t-esc="attrs.string || attrs.name"/>
|
||||
<span t-if="attrs.help">(?)</span>
|
||||
</label>
|
||||
<div style="white-space: nowrap;" t-att-id="element_id">
|
||||
<input t-att-name="attrs.name" type="text" class="field_date"
|
||||
t-att-value="defaults[attrs.name] || ''"
|
||||
t-att-autofocus="attrs.default_focus === '1' ? 'autofocus' : undefined"/>
|
||||
to
|
||||
<input t-att-name="attrs.name" type="text" class="field_date"
|
||||
t-att-value="defaults[attrs.name] || ''"/>
|
||||
<t t-if="filters.length" t-raw="filters.render(defaults)"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="SearchView.field.selection">
|
||||
<label style="display: block" t-att-title="attrs.help"
|
||||
t-att-for="element_id">
|
||||
|
@ -911,11 +1114,17 @@
|
|||
</t>
|
||||
<t t-name="SelectCreatePopup.search.buttons">
|
||||
<button type="button" class="oe_selectcreatepopup-search-select" disabled="disabled">Select</button>
|
||||
<button type="button" class="oe_selectcreatepopup-search-close">Close</button>
|
||||
<button type="button" class="oe_selectcreatepopup-search-close">Cancel</button>
|
||||
</t>
|
||||
<t t-name="SelectCreatePopup.form.buttons">
|
||||
<button type="button" class="oe_selectcreatepopup-form-save">Save</button>
|
||||
<button type="button" class="oe_selectcreatepopup-form-close">Close</button>
|
||||
<t t-if="widget.options.disable_multiple_selection">
|
||||
<button type="button" class="oe_selectcreatepopup-form-save">Save</button>
|
||||
</t>
|
||||
<t t-if="! widget.options.disable_multiple_selection">
|
||||
<button type="button" class="oe_selectcreatepopup-form-save-new">Save & New</button>
|
||||
<button type="button" class="oe_selectcreatepopup-form-save">Save & Close</button>
|
||||
</t>
|
||||
<button type="button" class="oe_selectcreatepopup-form-close">Cancel</button>
|
||||
</t>
|
||||
<t t-name="FormOpenPopup">
|
||||
<div t-att-id="element_id">
|
||||
|
@ -924,7 +1133,7 @@
|
|||
</t>
|
||||
<t t-name="FormOpenPopup.form.buttons">
|
||||
<button type="button" class="oe_formopenpopup-form-save">Save</button>
|
||||
<button type="button" class="oe_formopenpopup-form-close">Close</button>
|
||||
<button type="button" class="oe_formopenpopup-form-close">Cancel</button>
|
||||
</t>
|
||||
<t t-name="ListView.row.frame" t-extend="WidgetFrame">
|
||||
<t t-jquery="tr">
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
$(document).ready(function () {
|
||||
var openerp;
|
||||
module('base-class', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init();
|
||||
window.openerp.base.core(openerp);
|
||||
}
|
||||
});
|
||||
test('Basic class creation', function () {
|
||||
var C = openerp.base.Class.extend({
|
||||
foo: function () {
|
||||
return this.somevar;
|
||||
}
|
||||
});
|
||||
var instance = new C();
|
||||
instance.somevar = 3;
|
||||
|
||||
ok(instance instanceof C);
|
||||
strictEqual(instance.foo(), 3);
|
||||
});
|
||||
test('Class initialization', function () {
|
||||
var C1 = openerp.base.Class.extend({
|
||||
init: function () {
|
||||
this.foo = 3;
|
||||
}
|
||||
});
|
||||
var C2 = openerp.base.Class.extend({
|
||||
init: function (arg) {
|
||||
this.foo = arg;
|
||||
}
|
||||
});
|
||||
|
||||
var i1 = new C1(),
|
||||
i2 = new C2(42);
|
||||
|
||||
strictEqual(i1.foo, 3);
|
||||
strictEqual(i2.foo, 42);
|
||||
});
|
||||
test('Inheritance', function () {
|
||||
var C0 = openerp.base.Class.extend({
|
||||
foo: function () {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
var C1 = C0.extend({
|
||||
foo: function () {
|
||||
return 1 + this._super();
|
||||
}
|
||||
});
|
||||
var C2 = C1.extend({
|
||||
foo: function () {
|
||||
return 1 + this._super();
|
||||
}
|
||||
});
|
||||
|
||||
strictEqual(new C0().foo(), 1);
|
||||
strictEqual(new C1().foo(), 2);
|
||||
strictEqual(new C2().foo(), 3);
|
||||
});
|
||||
test('In-place extension', function () {
|
||||
var C0 = openerp.base.Class.extend({
|
||||
foo: function () {
|
||||
return 3;
|
||||
},
|
||||
qux: function () {
|
||||
return 3;
|
||||
},
|
||||
bar: 3
|
||||
});
|
||||
C0.include({
|
||||
foo: function () {
|
||||
return 5;
|
||||
},
|
||||
qux: function () {
|
||||
return 2 + this._super();
|
||||
},
|
||||
bar: 5,
|
||||
baz: 5
|
||||
});
|
||||
|
||||
strictEqual(new C0().bar, 5);
|
||||
strictEqual(new C0().baz, 5);
|
||||
strictEqual(new C0().foo(), 5);
|
||||
strictEqual(new C0().qux(), 5);
|
||||
});
|
||||
test('In-place extension and inheritance', function () {
|
||||
var C0 = openerp.base.Class.extend({
|
||||
foo: function () { return 1; },
|
||||
bar: function () { return 1; }
|
||||
});
|
||||
var C1 = C0.extend({
|
||||
foo: function () { return 1 + this._super(); }
|
||||
});
|
||||
strictEqual(new C1().foo(), 2);
|
||||
strictEqual(new C1().bar(), 1);
|
||||
|
||||
C1.include({
|
||||
foo: function () { return 2 + this._super(); },
|
||||
bar: function () { return 1 + this._super(); }
|
||||
});
|
||||
strictEqual(new C1().foo(), 4);
|
||||
strictEqual(new C1().bar(), 2);
|
||||
});
|
||||
test('In-place extensions alter existing instances', function () {
|
||||
var C0 = openerp.base.Class.extend({
|
||||
foo: function () { return 1; },
|
||||
bar: function () { return 1; }
|
||||
});
|
||||
var instance = new C0();
|
||||
strictEqual(instance.foo(), 1);
|
||||
strictEqual(instance.bar(), 1);
|
||||
|
||||
C0.include({
|
||||
foo: function () { return 2; },
|
||||
bar: function () { return 2 + this._super(); }
|
||||
});
|
||||
strictEqual(instance.foo(), 2);
|
||||
strictEqual(instance.bar(), 3);
|
||||
});
|
||||
test('In-place extension of subclassed types', function () {
|
||||
var C0 = openerp.base.Class.extend({
|
||||
foo: function () { return 1; },
|
||||
bar: function () { return 1; }
|
||||
});
|
||||
var C1 = C0.extend({
|
||||
foo: function () { return 1 + this._super(); },
|
||||
bar: function () { return 1 + this._super(); }
|
||||
});
|
||||
var instance = new C1();
|
||||
strictEqual(instance.foo(), 2);
|
||||
C0.include({
|
||||
foo: function () { return 2; },
|
||||
bar: function () { return 2 + this._super(); }
|
||||
});
|
||||
strictEqual(instance.foo(), 3);
|
||||
strictEqual(instance.bar(), 4);
|
||||
});
|
||||
});
|
|
@ -3,6 +3,7 @@ $(document).ready(function () {
|
|||
module("form.widget", {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init(true);
|
||||
window.openerp.base.core(openerp);
|
||||
window.openerp.base.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.base.data(openerp);
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
$(document).ready(function () {
|
||||
/**
|
||||
* Tests a jQuery collection against a selector ("ands" the .is() of each
|
||||
* member of the collection, instead of "or"-ing them)
|
||||
*
|
||||
* @param {jQuery} $c a jQuery collection object
|
||||
* @param {String} selector the selector to test the collection against
|
||||
*/
|
||||
var are = function ($c, selector) {
|
||||
return ($c.filter(function () { return $(this).is(selector); }).length
|
||||
=== $c.length);
|
||||
};
|
||||
|
||||
var fvg = {fields_view: {
|
||||
'fields': [],
|
||||
'arch': {
|
||||
'attrs': {string: ''}
|
||||
}
|
||||
}};
|
||||
|
||||
var openerp;
|
||||
module("ListView", {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.base.data(openerp);
|
||||
window.openerp.base.views(openerp);
|
||||
window.openerp.base.list(openerp);
|
||||
window.openerp.base.form(openerp);
|
||||
}
|
||||
});
|
||||
|
||||
test('render selection checkboxes', 2, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
listview.do_fill_table({records: [
|
||||
{data: {id: {value: null}}},
|
||||
{data: {id: {value: null}}},
|
||||
{data: {id: {value: null}}}
|
||||
]});
|
||||
|
||||
ok(are(listview.$element.find('tbody th'),
|
||||
'.oe-record-selector'));
|
||||
ok(are(listview.$element.find('tbody th input'),
|
||||
':checkbox:not([name])'));
|
||||
});
|
||||
test('render no checkbox if selectable=false', 1, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0}, false,
|
||||
{selectable: false});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
listview.do_fill_table({records: [
|
||||
{data: {id: {value: null}}},
|
||||
{data: {id: {value: null}}},
|
||||
{data: {id: {value: null}}}
|
||||
]});
|
||||
equal(listview.$element.find('tbody th').length, 0);
|
||||
});
|
||||
test('select a bunch of records', 2, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
null, 'qunit-fixture', {model: null, ids: [1, 2, 3], index: 0});
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
listview.do_fill_table({records: [
|
||||
{data: {id: {value: 1}}},
|
||||
{data: {id: {value: 2}}},
|
||||
{data: {id: {value: 3}}}
|
||||
]});
|
||||
// TODO: find less intrusive way to get selection count of list view?
|
||||
listview.$element.find('tbody th input:eq(2)')
|
||||
.attr('checked', true);
|
||||
deepEqual(listview.list.get_selection(), [3]);
|
||||
listview.$element.find('tbody th input:eq(1)')
|
||||
.attr('checked', true);
|
||||
deepEqual(listview.list.get_selection(), [2, 3]);
|
||||
});
|
||||
test('render deletion button if list is deletable', 1, function () {
|
||||
var listview = new openerp.base.ListView(
|
||||
null, 'qunit-fixture', {model: null, ids: [null, null, null], index: 0});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
listview.do_fill_table({records: [
|
||||
{data: {id: {value: null}}},
|
||||
{data: {id: {value: null}}},
|
||||
{data: {id: {value: null}}}
|
||||
]});
|
||||
equal(
|
||||
listview.$element.find('tbody tr td.oe-record-delete button').length,
|
||||
3);
|
||||
});
|
||||
test('deletion button should lead on deletion in the dataset',
|
||||
2, function () {
|
||||
var deleted;
|
||||
var listview = new openerp.base.ListView(
|
||||
null, 'qunit-fixture',
|
||||
{model: null, unlink: function (ids) {
|
||||
deleted = ids;
|
||||
}, ids: [1, 2, 3], index: 0});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
listview.do_fill_table({records: [
|
||||
{data: {id: {value: 1}}},
|
||||
{data: {id: {value: 2}}},
|
||||
{data: {id: {value: 3}}}
|
||||
]});
|
||||
listview.$element.find('tbody td.oe-record-delete:eq(2) button').click();
|
||||
deepEqual(deleted, [3]);
|
||||
listview.$element.find('tbody td.oe-record-delete:eq(0) button').click();
|
||||
deepEqual(deleted, [1]);
|
||||
});
|
||||
test('multiple records deletion', 1, function () {
|
||||
var deleted;
|
||||
var listview = new openerp.base.ListView(
|
||||
null, 'qunit-fixture',
|
||||
{model: null, unlink: function (ids) {
|
||||
deleted = ids;
|
||||
}, ids: [1, 2, 3], index: 0});
|
||||
|
||||
listview.on_loaded(fvg);
|
||||
|
||||
listview.do_fill_table({records: [
|
||||
{data: {id: {value: 1}}},
|
||||
{data: {id: {value: 2}}},
|
||||
{data: {id: {value: 3}}}
|
||||
]});
|
||||
listview.$element.find('tbody th input:eq(2)')
|
||||
.attr('checked', true);
|
||||
listview.$element.find('tbody th input:eq(1)')
|
||||
.attr('checked', true);
|
||||
|
||||
listview.$element.find('.oe-list-delete').click();
|
||||
deepEqual(deleted, [2, 3]);
|
||||
});
|
||||
});
|
|
@ -3,7 +3,7 @@ $(document).ready(function () {
|
|||
module('Registry', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.core(openerp);
|
||||
openerp.base.Foo = {};
|
||||
openerp.base.Bar = {};
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
$(document).ready(function () {
|
||||
var openerp;
|
||||
function get_widget(attrs) {
|
||||
var widget = new openerp.base.search.DateField(
|
||||
{attrs: attrs}, {name: 'foo'}, {inputs: []});
|
||||
$('#qunit-fixture').html(widget.render({}));
|
||||
widget.start();
|
||||
return widget;
|
||||
}
|
||||
|
||||
module('search-date', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.views(openerp);
|
||||
window.openerp.base.search(openerp);
|
||||
}
|
||||
});
|
||||
test('no values', function () {
|
||||
var widget = get_widget();
|
||||
deepEqual(widget.get_values(), {});
|
||||
strictEqual(widget.get_context(), null);
|
||||
strictEqual(widget.get_domain(), null);
|
||||
});
|
||||
test('filled from', function () {
|
||||
var widget = get_widget();
|
||||
widget.$element.find('input:eq(0)').val('1912-06-23');
|
||||
|
||||
deepEqual(widget.get_values(), {from: '1912-06-23'});
|
||||
strictEqual(widget.get_context(), null);
|
||||
deepEqual(widget.get_domain(), [['foo', '>=', '1912-06-23']]);
|
||||
});
|
||||
test('filled to', function () {
|
||||
var widget = get_widget();
|
||||
widget.$element.find('input:eq(1)').val('1954-06-07');
|
||||
|
||||
deepEqual(widget.get_values(), {to: '1954-06-07'});
|
||||
strictEqual(widget.get_context(), null);
|
||||
deepEqual(widget.get_domain(), [['foo', '<=', '1954-06-07']]);
|
||||
});
|
||||
test('filled both', function () {
|
||||
var widget = get_widget();
|
||||
widget.$element.find('input:eq(0)').val('1912-06-23');
|
||||
widget.$element.find('input:eq(1)').val('1954-06-07');
|
||||
|
||||
deepEqual(widget.get_values(), {from: '1912-06-23', to: '1954-06-07'});
|
||||
strictEqual(widget.get_context(), null);
|
||||
deepEqual(widget.get_domain(),
|
||||
[['foo', '>=', '1912-06-23'], ['foo', '<=', '1954-06-07']]);
|
||||
});
|
||||
test('custom context', function () {
|
||||
var widget = get_widget({context: {__id: -1}});
|
||||
widget.$element.find('input:eq(0)').val('1912-06-23');
|
||||
widget.$element.find('input:eq(1)').val('1954-06-07');
|
||||
|
||||
deepEqual(
|
||||
widget.get_context(),
|
||||
{__id: -1,
|
||||
own_values: {
|
||||
self: {from: '1912-06-23', to: '1954-06-07'}}});
|
||||
});
|
||||
test('custom filter_domain', function () {
|
||||
var widget = get_widget({filter_domain: {__id: -42}});
|
||||
widget.$element.find('input:eq(0)').val('1912-06-23');
|
||||
widget.$element.find('input:eq(1)').val('1954-06-07');
|
||||
|
||||
deepEqual(
|
||||
widget.get_domain(),
|
||||
{__id: -42,
|
||||
own_values: {
|
||||
self: {from: '1912-06-23', to: '1954-06-07'}}});
|
||||
});
|
||||
});
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP</title>
|
||||
<link rel="shortcut icon" href="/openobject/static/images/favicon.ico" type="image/x-icon"/>
|
||||
<link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
|
||||
<link rel="stylesheet" href="/base/static/lib/qunit/qunit-2011-23-22.css">
|
||||
<script src="/base/static/lib/qunit/qunit-2011-23-22.js" type="text/javascript"></script>
|
||||
|
@ -11,18 +11,18 @@
|
|||
<script src="/base/static/lib/underscore/underscore.js" type="text/javascript"></script>
|
||||
|
||||
<!-- jquery -->
|
||||
<script src="/base/static/lib/jquery/jquery-1.5.2.js"></script>
|
||||
<script src="/base/static/lib/jquery/jquery-1.6.2.js"></script>
|
||||
<script src="/base/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
|
||||
|
||||
<script src="/base/static/lib/qweb/qweb.js"></script>
|
||||
|
||||
<script src="/base/static/src/js/base.js"></script>
|
||||
<script src="/base/static/src/js/dates.js"></script>
|
||||
<script src="/base/static/src/js/boot.js"></script>
|
||||
<script src="/base/static/src/js/core.js"></script>
|
||||
<script src="/base/static/src/js/formats.js"></script>
|
||||
<script src="/base/static/src/js/chrome.js"></script>
|
||||
<script src="/base/static/src/js/data.js"></script>
|
||||
<script src="/base/static/src/js/views.js"></script>
|
||||
<script src="/base/static/src/js/search.js"></script>
|
||||
<script src="/base/static/src/js/m2o.js"></script>
|
||||
<script src="/base/static/src/js/form.js"></script>
|
||||
<script src="/base/static/src/js/list.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
@ -37,8 +37,7 @@
|
|||
<ol id="qunit-tests"></ol>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
<script type="text/javascript" src="/base/static/test/class.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/registry.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/search-date.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/form.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/list.js"></script>
|
||||
</html>
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
"version": "2.0",
|
||||
"depends": ['base'],
|
||||
"js": [
|
||||
'static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.js',
|
||||
'static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler_debug.js',
|
||||
'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js',
|
||||
'static/src/js/calendar.js'
|
||||
],
|
||||
"css": ['static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.css'],
|
||||
"css": ['static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.css',
|
||||
'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_ext.css'
|
||||
],
|
||||
'active': True
|
||||
}
|
||||
|
|
|
@ -1,356 +1,10 @@
|
|||
from base.controllers.main import View
|
||||
import openerpweb, time, math, re, datetime as DT, pytz
|
||||
|
||||
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 []
|
||||
import openerpweb
|
||||
|
||||
class CalendarView(View):
|
||||
_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
|
||||
def load(self, req, model, view_id):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'calendar')
|
||||
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]}
|
||||
def load(self, req, model, view_id, toolbar=False):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'calendar', toolbar=toolbar)
|
||||
return {'fields_view': fields_view}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
<h1>GNU GENERAL PUBLIC LICENSE</h1>
|
||||
Version 2, June 1991 </p>
|
||||
</p>
|
||||
<p>Copyright (C) 1989, 1991 Free Software Foundation, Inc. </p>
|
||||
<p>59 Temple Place - Suite 330, Boston, MA 02111-1307, USA</p>
|
||||
</p>
|
||||
<p>Everyone is permitted to copy and distribute verbatim copies</p>
|
||||
<p>of this license document, but changing it is not allowed.</p>
|
||||
</p>
|
||||
</p>
|
||||
<p>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</p>
|
||||
<p>0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". </p>
|
||||
</p>
|
||||
<p>Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. </p>
|
||||
</p>
|
||||
<p>1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. </p>
|
||||
</p>
|
||||
<p>You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. </p>
|
||||
</p>
|
||||
<p>2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: </p>
|
||||
</p>
|
||||
</p>
|
||||
<p>a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. </p>
|
||||
</p>
|
||||
<p>b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. </p>
|
||||
</p>
|
||||
<p>c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) </p>
|
||||
<p>These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. </p>
|
||||
</p>
|
||||
<p>Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. </p>
|
||||
</p>
|
||||
<p>In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. </p>
|
||||
</p>
|
||||
<p>3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: </p>
|
||||
</p>
|
||||
<p>a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </p>
|
||||
</p>
|
||||
<p>b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </p>
|
||||
</p>
|
||||
<p>c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) </p>
|
||||
<p>The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. </p>
|
||||
</p>
|
||||
<p>If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. </p>
|
||||
</p>
|
||||
<p>4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. </p>
|
||||
</p>
|
||||
<p>5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. </p>
|
||||
</p>
|
||||
<p>6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. </p>
|
||||
</p>
|
||||
<p>7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. </p>
|
||||
</p>
|
||||
<p>If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. </p>
|
||||
</p>
|
||||
<p>It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. </p>
|
||||
</p>
|
||||
<p>This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. </p>
|
||||
</p>
|
||||
<p>8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. </p>
|
||||
</p>
|
||||
<p>9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. </p>
|
||||
</p>
|
||||
<p>Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. </p>
|
||||
</p>
|
||||
<p>10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. </p>
|
||||
</p>
|
||||
<p>NO WARRANTY</p>
|
||||
</p>
|
||||
<p>11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. </p>
|
||||
</p>
|
||||
<p>12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. </p>
|
||||
</p>
|
||||
<p>
|
|
@ -0,0 +1,706 @@
|
|||
<?php
|
||||
|
||||
require_once("tools.php");
|
||||
require_once("db_common.php");
|
||||
require_once("dataprocessor.php");
|
||||
require_once("update.php");
|
||||
|
||||
//enable buffering to catch and ignore any custom output before XML generation
|
||||
//because of this command, it strongly recommended to include connector's file before any other libs
|
||||
//in such case it will handle any extra output from not well formed code of other libs
|
||||
ini_set("output_buffering","On");
|
||||
ob_start();
|
||||
|
||||
class OutputWriter{
|
||||
private $start;
|
||||
private $end;
|
||||
private $type;
|
||||
|
||||
public function __construct($start, $end = ""){
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
$this->type = "xml";
|
||||
}
|
||||
public function add($add){
|
||||
$this->start.=$add;
|
||||
}
|
||||
public function reset(){
|
||||
$this->start="";
|
||||
$this->end="";
|
||||
}
|
||||
public function set_type($add){
|
||||
$this->type=$add;
|
||||
}
|
||||
public function output($name="", $inline=true){
|
||||
ob_clean();
|
||||
if ($this->type == "xml")
|
||||
header("Content-type: text/xml");
|
||||
|
||||
echo $this->__toString();
|
||||
}
|
||||
public function __toString(){
|
||||
return $this->start.$this->end;
|
||||
}
|
||||
}
|
||||
|
||||
/*! EventInterface
|
||||
Base class , for iterable collections, which are used in event
|
||||
**/
|
||||
class EventInterface{
|
||||
protected $request; ////!< DataRequestConfig instance
|
||||
public $rules=array(); //!< array of sorting rules
|
||||
|
||||
/*! constructor
|
||||
creates a new interface based on existing request
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
*/
|
||||
public function __construct($request){
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/*! remove all elements from collection
|
||||
*/
|
||||
public function clear(){
|
||||
array_splice($rules,0);
|
||||
}
|
||||
/*! get index by name
|
||||
|
||||
@param name
|
||||
name of field
|
||||
@return
|
||||
index of named field
|
||||
*/
|
||||
public function index($name){
|
||||
$len = sizeof($this->rules);
|
||||
for ($i=0; $i < $len; $i++) {
|
||||
if ($this->rules[$i]["name"]==$name)
|
||||
return $i;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*! Wrapper for collection of sorting rules
|
||||
**/
|
||||
class SortInterface extends EventInterface{
|
||||
/*! constructor
|
||||
creates a new interface based on existing request
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
*/
|
||||
public function __construct($request){
|
||||
parent::__construct($request);
|
||||
$this->rules = &$request->get_sort_by_ref();
|
||||
}
|
||||
/*! add new sorting rule
|
||||
|
||||
@param name
|
||||
name of field
|
||||
@param dir
|
||||
direction of sorting
|
||||
*/
|
||||
public function add($name,$dir){
|
||||
$this->request->set_sort($name,$dir);
|
||||
}
|
||||
public function store(){
|
||||
$this->request->set_sort_by($this->rules);
|
||||
}
|
||||
}
|
||||
/*! Wrapper for collection of filtering rules
|
||||
**/
|
||||
class FilterInterface extends EventInterface{
|
||||
/*! constructor
|
||||
creates a new interface based on existing request
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
*/
|
||||
public function __construct($request){
|
||||
$this->request = $request;
|
||||
$this->rules = &$request->get_filters_ref();
|
||||
}
|
||||
/*! add new filatering rule
|
||||
|
||||
@param name
|
||||
name of field
|
||||
@param value
|
||||
value to filter by
|
||||
@param rule
|
||||
filtering rule
|
||||
*/
|
||||
public function add($name,$value,$rule){
|
||||
$this->request->set_filter($name,$value,$rule);
|
||||
}
|
||||
public function store(){
|
||||
$this->request->set_filters($this->rules);
|
||||
}
|
||||
}
|
||||
|
||||
/*! base class for component item representation
|
||||
**/
|
||||
class DataItem{
|
||||
protected $data; //!< hash of data
|
||||
protected $config;//!< DataConfig instance
|
||||
protected $index;//!< index of element
|
||||
protected $skip;//!< flag , which set if element need to be skiped during rendering
|
||||
/*! constructor
|
||||
|
||||
@param data
|
||||
hash of data
|
||||
@param config
|
||||
DataConfig object
|
||||
@param index
|
||||
index of element
|
||||
*/
|
||||
function __construct($data,$config,$index){
|
||||
$this->config=$config;
|
||||
$this->data=$data;
|
||||
$this->index=$index;
|
||||
$this->skip=false;
|
||||
}
|
||||
/*! get named value
|
||||
|
||||
@param name
|
||||
name or alias of field
|
||||
@return
|
||||
value from field with provided name or alias
|
||||
*/
|
||||
public function get_value($name){
|
||||
return $this->data[$name];
|
||||
}
|
||||
/*! set named value
|
||||
|
||||
@param name
|
||||
name or alias of field
|
||||
@param value
|
||||
value for field with provided name or alias
|
||||
*/
|
||||
public function set_value($name,$value){
|
||||
return $this->data[$name]=$value;
|
||||
}
|
||||
/*! get id of element
|
||||
@return
|
||||
id of element
|
||||
*/
|
||||
public function get_id(){
|
||||
$id = $this->config->id["name"];
|
||||
if (array_key_exists($id,$this->data))
|
||||
return $this->data[$id];
|
||||
return false;
|
||||
}
|
||||
/*! change id of element
|
||||
|
||||
@param value
|
||||
new id value
|
||||
*/
|
||||
public function set_id($value){
|
||||
$this->data[$this->config->id["name"]]=$value;
|
||||
}
|
||||
/*! get index of element
|
||||
|
||||
@return
|
||||
index of element
|
||||
*/
|
||||
public function get_index(){
|
||||
return $this->index;
|
||||
}
|
||||
/*! mark element for skiping ( such element will not be rendered )
|
||||
*/
|
||||
public function skip(){
|
||||
$this->skip=true;
|
||||
}
|
||||
|
||||
/*! return self as XML string
|
||||
*/
|
||||
public function to_xml(){
|
||||
return $this->to_xml_start().$this->to_xml_end();
|
||||
}
|
||||
|
||||
/*! replace xml unsafe characters
|
||||
|
||||
@param string
|
||||
string to be escaped
|
||||
@return
|
||||
escaped string
|
||||
*/
|
||||
protected function xmlentities($string) {
|
||||
return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string);
|
||||
}
|
||||
|
||||
/*! return starting tag for self as XML string
|
||||
*/
|
||||
public function to_xml_start(){
|
||||
$str="<item";
|
||||
for ($i=0; $i < sizeof($this->config->data); $i++){
|
||||
$name=$this->config->data[$i]["name"];
|
||||
$str.=" ".$name."='".$this->xmlentities($this->data[$name])."'";
|
||||
}
|
||||
return $str.">";
|
||||
}
|
||||
/*! return ending tag for XML string
|
||||
*/
|
||||
public function to_xml_end(){
|
||||
return "</item>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! Base connector class
|
||||
This class used as a base for all component specific connectors.
|
||||
Can be used on its own to provide raw data.
|
||||
**/
|
||||
class Connector {
|
||||
protected $config;//DataConfig instance
|
||||
protected $request;//DataRequestConfig instance
|
||||
protected $names;//!< hash of names for used classes
|
||||
private $encoding="utf-8";//!< assigned encoding (UTF-8 by default)
|
||||
private $editing=false;//!< flag of edit mode ( response for dataprocessor )
|
||||
private $updating=false;//!< flag of update mode ( response for data-update )
|
||||
private $db; //!< db connection resource
|
||||
protected $dload;//!< flag of dyn. loading mode
|
||||
public $access; //!< AccessMaster instance
|
||||
|
||||
public $sql; //DataWrapper instance
|
||||
public $event; //EventMaster instance
|
||||
public $limit=false;
|
||||
|
||||
private $id_seed=0; //!< default value, used to generate auto-IDs
|
||||
protected $live_update = false; // actions table name for autoupdating
|
||||
|
||||
/*! constructor
|
||||
|
||||
Here initilization of all Masters occurs, execution timer initialized
|
||||
@param db
|
||||
db connection resource
|
||||
@param type
|
||||
string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided
|
||||
@param item_type
|
||||
name of class, which will be used for item rendering, optional, DataItem will be used by default
|
||||
@param data_type
|
||||
name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default.
|
||||
*/
|
||||
public function __construct($db,$type=false, $item_type=false, $data_type=false){
|
||||
$this->exec_time=microtime(true);
|
||||
|
||||
if (!$type) $type="MySQL";
|
||||
if (class_exists($type."DBDataWrapper",false)) $type.="DBDataWrapper";
|
||||
if (!$item_type) $item_type="DataItem";
|
||||
if (!$data_type) $data_type="DataProcessor";
|
||||
|
||||
$this->names=array(
|
||||
"db_class"=>$type,
|
||||
"item_class"=>$item_type,
|
||||
"data_class"=>$data_type,
|
||||
);
|
||||
|
||||
$this->config = new DataConfig();
|
||||
$this->request = new DataRequestConfig();
|
||||
$this->event = new EventMaster();
|
||||
$this->access = new AccessMaster();
|
||||
|
||||
if (!class_exists($this->names["db_class"],false))
|
||||
throw new Exception("DB class not found: ".$this->names["db_class"]);
|
||||
$this->sql = new $this->names["db_class"]($db,$this->config);
|
||||
|
||||
$this->db=$db;//saved for options connectors, if any
|
||||
|
||||
EventMaster::trigger_static("connectorCreate",$this);
|
||||
}
|
||||
|
||||
/*! return db connection resource
|
||||
nested class may neeed to access live connection object
|
||||
@return
|
||||
DB connection resource
|
||||
*/
|
||||
protected function get_connection(){
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
public function get_config(){
|
||||
return new DataConfig($this->config);
|
||||
}
|
||||
|
||||
public function get_request(){
|
||||
return new DataRequestConfig($this->config);
|
||||
}
|
||||
|
||||
|
||||
/*! config connector based on table
|
||||
|
||||
@param table
|
||||
name of table in DB
|
||||
@param id
|
||||
name of id field
|
||||
@param fields
|
||||
list of fields names
|
||||
@param extra
|
||||
list of extra fields, optional, such fields will not be included in data rendering, but will be accessible in all inner events
|
||||
@param relation_id
|
||||
name of field used to define relations for hierarchical data organization, optional
|
||||
*/
|
||||
public function render_table($table,$id="",$fields=false,$extra=false,$relation_id=false){
|
||||
$this->configure($table,$id,$fields,$extra,$relation_id);
|
||||
return $this->render();
|
||||
}
|
||||
public function configure($table,$id="",$fields=false,$extra=false,$relation_id=false){
|
||||
if ($fields === false){
|
||||
//auto-config
|
||||
$info = $this->sql->fields_list($table);
|
||||
$fields = implode(",",$info["fields"]);
|
||||
if ($info["key"])
|
||||
$id = $info["key"];
|
||||
}
|
||||
$this->config->init($id,$fields,$extra,$relation_id);
|
||||
$this->request->set_source($table);
|
||||
}
|
||||
|
||||
protected function uuid(){
|
||||
return time()."x".$this->id_seed++;
|
||||
}
|
||||
|
||||
/*! config connector based on sql
|
||||
|
||||
@param sql
|
||||
sql query used as base of configuration
|
||||
@param id
|
||||
name of id field
|
||||
@param fields
|
||||
list of fields names
|
||||
@param extra
|
||||
list of extra fields, optional, such fields will not be included in data rendering, but will be accessible in all inner events
|
||||
@param relation_id
|
||||
name of field used to define relations for hierarchical data organization, optional
|
||||
*/
|
||||
public function render_sql($sql,$id,$fields,$extra=false,$relation_id=false){
|
||||
$this->config->init($id,$fields,$extra,$relation_id);
|
||||
$this->request->parse_sql($sql);
|
||||
return $this->render();
|
||||
}
|
||||
|
||||
/*! render already configured connector
|
||||
|
||||
@param config
|
||||
configuration of data
|
||||
@param request
|
||||
configuraton of request
|
||||
*/
|
||||
public function render_connector($config,$request){
|
||||
$this->config->copy($config);
|
||||
$this->request->copy($request);
|
||||
return $this->render();
|
||||
}
|
||||
|
||||
/*! render self
|
||||
process commands, output requested data as XML
|
||||
*/
|
||||
public function render(){
|
||||
EventMaster::trigger_static("connectorInit",$this);
|
||||
|
||||
$this->parse_request();
|
||||
if ($this->live_update !== false && $this->updating!==false) {
|
||||
$this->live_update->get_updates();
|
||||
} else {
|
||||
if ($this->editing){
|
||||
$dp = new $this->names["data_class"]($this,$this->config,$this->request);
|
||||
$dp->process($this->config,$this->request);
|
||||
}
|
||||
else {
|
||||
$wrap = new SortInterface($this->request);
|
||||
$this->event->trigger("beforeSort",$wrap);
|
||||
$wrap->store();
|
||||
|
||||
$wrap = new FilterInterface($this->request);
|
||||
$this->event->trigger("beforeFilter",$wrap);
|
||||
$wrap->store();
|
||||
|
||||
$this->output_as_xml( $this->sql->select($this->request) );
|
||||
}
|
||||
}
|
||||
$this->end_run();
|
||||
}
|
||||
|
||||
/*! prevent SQL injection through column names
|
||||
replace dangerous chars in field names
|
||||
@param str
|
||||
incoming field name
|
||||
@return
|
||||
safe field name
|
||||
*/
|
||||
protected function safe_field_name($str){
|
||||
return strtok($str, " \n\t;',");
|
||||
}
|
||||
|
||||
/*! limit max count of records
|
||||
connector will ignore any records after outputing max count
|
||||
@param limit
|
||||
max count of records
|
||||
@return
|
||||
none
|
||||
*/
|
||||
public function set_limit($limit){
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
protected function parse_request_mode(){
|
||||
//detect edit mode
|
||||
if (isset($_GET["editing"])){
|
||||
$this->editing=true;
|
||||
} else if (isset($_POST["ids"])){
|
||||
$this->editing=true;
|
||||
LogMaster::log('While there is no edit mode mark, POST parameters similar to edit mode detected. \n Switching to edit mode ( to disable behavior remove POST[ids]');
|
||||
} else if (isset($_GET['dhx_version'])){
|
||||
$this->updating = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*! parse incoming request, detects commands and modes
|
||||
*/
|
||||
protected function parse_request(){
|
||||
//set default dyn. loading params, can be reset in child classes
|
||||
if ($this->dload)
|
||||
$this->request->set_limit(0,$this->dload);
|
||||
else if ($this->limit)
|
||||
$this->request->set_limit(0,$this->limit);
|
||||
|
||||
$this->parse_request_mode();
|
||||
|
||||
if ($this->live_update && ($this->updating || $this->editing)){
|
||||
$this->request->set_version($_GET["dhx_version"]);
|
||||
$this->request->set_user($_GET["dhx_user"]);
|
||||
}
|
||||
|
||||
if (isset($_GET["dhx_sort"]))
|
||||
foreach($_GET["dhx_sort"] as $k => $v){
|
||||
$k = $this->safe_field_name($k);
|
||||
$this->request->set_sort($this->resolve_parameter($k),$v);
|
||||
}
|
||||
|
||||
if (isset($_GET["dhx_filter"]))
|
||||
foreach($_GET["dhx_filter"] as $k => $v){
|
||||
$k = $this->safe_field_name($k);
|
||||
$this->request->set_filter($this->resolve_parameter($k),$v);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*! convert incoming request name to the actual DB name
|
||||
@param name
|
||||
incoming parameter name
|
||||
@return
|
||||
name of related DB field
|
||||
*/
|
||||
protected function resolve_parameter($name){
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
/*! replace xml unsafe characters
|
||||
|
||||
@param string
|
||||
string to be escaped
|
||||
@return
|
||||
escaped string
|
||||
*/
|
||||
private function xmlentities($string) {
|
||||
return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string);
|
||||
}
|
||||
|
||||
/*! render from DB resultset
|
||||
@param res
|
||||
DB resultset
|
||||
process commands, output requested data as XML
|
||||
*/
|
||||
protected function render_set($res){
|
||||
$output="";
|
||||
$index=0;
|
||||
$this->event->trigger("beforeRenderSet",$this,$res,$this->config);
|
||||
while ($data=$this->sql->get_next($res)){
|
||||
$data = new $this->names["item_class"]($data,$this->config,$index);
|
||||
if ($data->get_id()===false)
|
||||
$data->set_id($this->uuid());
|
||||
$this->event->trigger("beforeRender",$data);
|
||||
$output.=$data->to_xml();
|
||||
$index++;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/*! output fetched data as XML
|
||||
@param res
|
||||
DB resultset
|
||||
*/
|
||||
protected function output_as_xml($res){
|
||||
$start="<?xml version='1.0' encoding='".$this->encoding."' ?>".$this->xml_start();
|
||||
$end=$this->render_set($res).$this->xml_end();
|
||||
|
||||
$out = new OutputWriter($start, $end);
|
||||
$this->event->trigger("beforeOutput", $this, $out);
|
||||
|
||||
$out->output();
|
||||
}
|
||||
|
||||
|
||||
/*! end processing
|
||||
stop execution timer, kill the process
|
||||
*/
|
||||
protected function end_run(){
|
||||
$time=microtime(true)-$this->exec_time;
|
||||
LogMaster::log("Done in {$time}s");
|
||||
flush();
|
||||
die();
|
||||
}
|
||||
|
||||
/*! set xml encoding
|
||||
|
||||
methods sets only attribute in XML, no real encoding conversion occurs
|
||||
@param encoding
|
||||
value which will be used as XML encoding
|
||||
*/
|
||||
public function set_encoding($encoding){
|
||||
$this->encoding=$encoding;
|
||||
}
|
||||
|
||||
/*! enable or disable dynamic loading mode
|
||||
|
||||
@param count
|
||||
count of rows loaded from server, actual only for grid-connector, can be skiped in other cases.
|
||||
If value is a false or 0 - dyn. loading will be disabled
|
||||
*/
|
||||
public function dynamic_loading($count){
|
||||
$this->dload=$count;
|
||||
}
|
||||
|
||||
/*! enable logging
|
||||
|
||||
@param path
|
||||
path to the log file. If set as false or empty strig - logging will be disabled
|
||||
@param client_log
|
||||
enable output of log data to the client side
|
||||
*/
|
||||
public function enable_log($path=true,$client_log=false){
|
||||
LogMaster::enable_log($path,$client_log);
|
||||
}
|
||||
|
||||
/*! provides infor about current processing mode
|
||||
@return
|
||||
true if processing dataprocessor command, false otherwise
|
||||
*/
|
||||
public function is_select_mode(){
|
||||
$this->parse_request_mode();
|
||||
return !$this->editing;
|
||||
}
|
||||
|
||||
public function is_first_call(){
|
||||
$this->parse_request_mode();
|
||||
return !($this->editing || $this->updating || $this->request->get_start() || sizeof($this->request->get_filters()) || sizeof($this->request->get_sort_by()));
|
||||
|
||||
}
|
||||
|
||||
/*! renders self as xml, starting part
|
||||
*/
|
||||
protected function xml_start(){
|
||||
return "<data>";
|
||||
}
|
||||
/*! renders self as xml, ending part
|
||||
*/
|
||||
protected function xml_end(){
|
||||
return "</data>";
|
||||
}
|
||||
|
||||
|
||||
public function insert($data) {
|
||||
$action = new DataAction('inserted', false, $data);
|
||||
$request = new DataRequestConfig();
|
||||
$request->set_source($this->request->get_source());
|
||||
|
||||
$this->config->limit_fields($data);
|
||||
$this->sql->insert($action,$request);
|
||||
$this->config->restore_fields($data);
|
||||
|
||||
return $action->get_new_id();
|
||||
}
|
||||
|
||||
public function delete($id) {
|
||||
$action = new DataAction('deleted', $id, array());
|
||||
$request = new DataRequestConfig();
|
||||
$request->set_source($this->request->get_source());
|
||||
|
||||
$this->sql->delete($action,$request);
|
||||
return $action->get_status();
|
||||
}
|
||||
|
||||
public function update($data) {
|
||||
$action = new DataAction('updated', $data[$this->config->id["name"]], $data);
|
||||
$request = new DataRequestConfig();
|
||||
$request->set_source($this->request->get_source());
|
||||
|
||||
$this->config->limit_fields($data);
|
||||
$this->sql->update($action,$request);
|
||||
$this->config->restore_fields($data);
|
||||
|
||||
return $action->get_status();
|
||||
}
|
||||
|
||||
/*! sets actions_table for Optimistic concurrency control mode and start it
|
||||
@param table_name
|
||||
name of database table which will used for saving actions
|
||||
@param url
|
||||
url used for update notifications
|
||||
*/
|
||||
public function enable_live_update($table, $url=false){
|
||||
$this->live_update = new DataUpdate($this->sql, $this->config, $this->request, $table,$url);
|
||||
$this->live_update->set_event($this->event,$this->names["item_class"]);
|
||||
$this->event->attach("beforeOutput", Array($this->live_update, "version_output"));
|
||||
$this->event->attach("beforeFiltering", Array($this->live_update, "get_updates"));
|
||||
$this->event->attach("beforeProcessing", Array($this->live_update, "check_collision"));
|
||||
$this->event->attach("afterProcessing", Array($this->live_update, "log_operations"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! wrapper around options collection, used for comboboxes and filters
|
||||
**/
|
||||
class OptionsConnector extends Connector{
|
||||
protected $init_flag=false;//!< used to prevent rendering while initialization
|
||||
public function __construct($res,$type=false,$item_type=false,$data_type=false){
|
||||
if (!$item_type) $item_type="DataItem";
|
||||
if (!$data_type) $data_type=""; //has not sense, options not editable
|
||||
parent::__construct($res,$type,$item_type,$data_type);
|
||||
}
|
||||
/*! render self
|
||||
process commands, return data as XML, not output data to stdout, ignore parameters in incoming request
|
||||
@return
|
||||
data as XML string
|
||||
*/
|
||||
public function render(){
|
||||
if (!$this->init_flag){
|
||||
$this->init_flag=true;
|
||||
return "";
|
||||
}
|
||||
$res = $this->sql->select($this->request);
|
||||
return $this->render_set($res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class DistinctOptionsConnector extends OptionsConnector{
|
||||
/*! render self
|
||||
process commands, return data as XML, not output data to stdout, ignore parameters in incoming request
|
||||
@return
|
||||
data as XML string
|
||||
*/
|
||||
public function render(){
|
||||
if (!$this->init_flag){
|
||||
$this->init_flag=true;
|
||||
return "";
|
||||
}
|
||||
$res = $this->sql->get_variants($this->config->text[0]["db_name"],$this->request);
|
||||
return $this->render_set($res);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
require_once("base_connector.php");
|
||||
/*! DataItem class for Combo component
|
||||
**/
|
||||
class ComboDataItem extends DataItem{
|
||||
private $selected;//!< flag of selected option
|
||||
|
||||
function __construct($data,$config,$index){
|
||||
parent::__construct($data,$config,$index);
|
||||
|
||||
$this->selected=false;
|
||||
}
|
||||
/*! mark option as selected
|
||||
*/
|
||||
function select(){
|
||||
$this->selected=true;
|
||||
}
|
||||
/*! return self as XML string, starting part
|
||||
*/
|
||||
function to_xml_start(){
|
||||
if ($this->skip) return "";
|
||||
|
||||
return "<option ".($this->selected?"selected='true'":"")."value='".$this->get_id()."'><![CDATA[".$this->data[$this->config->text[0]["name"]]."]]>";
|
||||
}
|
||||
/*! return self as XML string, ending part
|
||||
*/
|
||||
function to_xml_end(){
|
||||
if ($this->skip) return "";
|
||||
return "</option>";
|
||||
}
|
||||
}
|
||||
|
||||
/*! Connector for the dhtmlxCombo
|
||||
**/
|
||||
class ComboConnector extends Connector{
|
||||
private $filter; //!< filtering mask from incoming request
|
||||
private $position; //!< position from incoming request
|
||||
|
||||
/*! constructor
|
||||
|
||||
Here initilization of all Masters occurs, execution timer initialized
|
||||
@param res
|
||||
db connection resource
|
||||
@param type
|
||||
string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided
|
||||
@param item_type
|
||||
name of class, which will be used for item rendering, optional, DataItem will be used by default
|
||||
@param data_type
|
||||
name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default.
|
||||
*/
|
||||
public function __construct($res,$type=false,$item_type=false,$data_type=false){
|
||||
if (!$item_type) $item_type="ComboDataItem";
|
||||
parent::__construct($res,$type,$item_type,$data_type);
|
||||
}
|
||||
|
||||
//parse GET scoope, all operations with incoming request must be done here
|
||||
function parse_request(){
|
||||
parent::parse_request();
|
||||
|
||||
if (isset($_GET["pos"])){
|
||||
if (!$this->dload) //not critical, so just write a log message
|
||||
LogMaster::log("Dyn loading request received, but server side was not configured to process dyn. loading. ");
|
||||
else
|
||||
$this->request->set_limit($_GET["pos"],$this->dload);
|
||||
}
|
||||
|
||||
if (isset($_GET["mask"]))
|
||||
$this->request->set_filter($this->config->text[0]["name"],$_GET["mask"]."%","LIKE");
|
||||
|
||||
LogMaster::log($this->request);
|
||||
}
|
||||
|
||||
|
||||
/*! renders self as xml, starting part
|
||||
*/
|
||||
public function xml_start(){
|
||||
if ($this->request->get_start())
|
||||
return "<complete add='true'>";
|
||||
else
|
||||
return "<complete>";
|
||||
}
|
||||
|
||||
/*! renders self as xml, ending part
|
||||
*/
|
||||
public function xml_end(){
|
||||
return "</complete>";
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
/*
|
||||
dhx_sort[index]=direction
|
||||
dhx_filter[index]=mask
|
||||
*/
|
||||
if (window.dhtmlXGridObject){
|
||||
dhtmlXGridObject.prototype._init_point_connector=dhtmlXGridObject.prototype._init_point;
|
||||
dhtmlXGridObject.prototype._init_point=function(){
|
||||
var clear_url=function(url){
|
||||
url=url.replace(/(\?|\&)connector[^\f]*/g,"");
|
||||
return url+(url.indexOf("?")!=-1?"&":"?")+"connector=true";
|
||||
}
|
||||
var combine_urls=function(url){
|
||||
return clear_url(url)+(this._connector_sorting||"")+(this._connector_filter||"");
|
||||
}
|
||||
var sorting_url=function(url,ind,dir){
|
||||
this._connector_sorting="&dhx_sort["+ind+"]="+dir;
|
||||
return combine_urls.call(this,url);
|
||||
}
|
||||
var filtering_url=function(url,inds,vals){
|
||||
for (var i=0; i<inds.length; i++)
|
||||
inds[i]="dhx_filter["+inds[i]+"]="+encodeURIComponent(vals[i]);
|
||||
this._connector_filter="&"+inds.join("&");
|
||||
return combine_urls.call(this,url);
|
||||
}
|
||||
this.attachEvent("onCollectValues",function(ind){
|
||||
if (this._con_f_used[ind]){
|
||||
if (typeof(this._con_f_used[ind]) == "object")
|
||||
return this._con_f_used[ind];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
this.attachEvent("onDynXLS",function(){
|
||||
this.xmlFileUrl=combine_urls.call(this,this.xmlFileUrl);
|
||||
return true;
|
||||
});
|
||||
this.attachEvent("onBeforeSorting",function(ind,type,dir){
|
||||
if (type=="connector"){
|
||||
var self=this;
|
||||
this.clearAndLoad(sorting_url.call(this,this.xmlFileUrl,ind,dir),function(){
|
||||
self.setSortImgState(true,ind,dir);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
this.attachEvent("onFilterStart",function(a,b){
|
||||
if (this._con_f_used.length){
|
||||
this.clearAndLoad(filtering_url.call(this,this.xmlFileUrl,a,b));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
this.attachEvent("onXLE",function(a,b,c,xml){
|
||||
if (!xml) return;
|
||||
});
|
||||
|
||||
if (this._init_point_connector) this._init_point_connector();
|
||||
}
|
||||
dhtmlXGridObject.prototype._con_f_used=[];
|
||||
dhtmlXGridObject.prototype._in_header_connector_text_filter=function(t,i){
|
||||
if (!this._con_f_used[i])
|
||||
this._con_f_used[i]=1;
|
||||
return this._in_header_text_filter(t,i);
|
||||
}
|
||||
dhtmlXGridObject.prototype._in_header_connector_select_filter=function(t,i){
|
||||
if (!this._con_f_used[i])
|
||||
this._con_f_used[i]=2;
|
||||
return this._in_header_select_filter(t,i);
|
||||
}
|
||||
dhtmlXGridObject.prototype.load_connector=dhtmlXGridObject.prototype.load;
|
||||
dhtmlXGridObject.prototype.load=function(url, call, type){
|
||||
if (!this._colls_loaded && this.cellType){
|
||||
var ar=[];
|
||||
for (var i=0; i < this.cellType.length; i++)
|
||||
if (this.cellType[i].indexOf("co")==0 || this._con_f_used[i]==2) ar.push(i);
|
||||
if (ar.length)
|
||||
arguments[0]+=(arguments[0].indexOf("?")!=-1?"&":"?")+"connector=true&dhx_colls="+ar.join(",");
|
||||
}
|
||||
return this.load_connector.apply(this,arguments);
|
||||
}
|
||||
dhtmlXGridObject.prototype._parseHead_connector=dhtmlXGridObject.prototype._parseHead;
|
||||
dhtmlXGridObject.prototype._parseHead=function(url, call, type){
|
||||
this._parseHead_connector.apply(this,arguments);
|
||||
if (!this._colls_loaded){
|
||||
var cols = this.xmlLoader.doXPath("./coll_options", arguments[0]);
|
||||
for (var i=0; i < cols.length; i++){
|
||||
var f = cols[i].getAttribute("for");
|
||||
var v = [];
|
||||
var combo=null;
|
||||
if (this.cellType[f] == "combo")
|
||||
combo = this.getColumnCombo(f);
|
||||
if (this.cellType[f].indexOf("co")==0)
|
||||
combo=this.getCombo(f);
|
||||
|
||||
var os = this.xmlLoader.doXPath("./item",cols[i]);
|
||||
for (var j=0; j<os.length; j++){
|
||||
var val=os[j].getAttribute("value");
|
||||
|
||||
if (combo){
|
||||
var lab=os[j].getAttribute("label")||val;
|
||||
|
||||
if (combo.addOption)
|
||||
combo.addOption([[val, lab]]);
|
||||
else
|
||||
combo.put(val,lab);
|
||||
|
||||
v[v.length]=lab;
|
||||
} else
|
||||
v[v.length]=val;
|
||||
}
|
||||
if (this._con_f_used[f*1])
|
||||
this._con_f_used[f*1]=v;
|
||||
};
|
||||
this._colls_loaded=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (window.dataProcessor){
|
||||
dataProcessor.prototype.init_original=dataProcessor.prototype.init;
|
||||
dataProcessor.prototype.init=function(obj){
|
||||
this.init_original(obj);
|
||||
obj._dataprocessor=this;
|
||||
|
||||
this.setTransactionMode("POST",true);
|
||||
this.serverProcessor+=(this.serverProcessor.indexOf("?")!=-1?"&":"?")+"editing=true";
|
||||
}
|
||||
}
|
||||
dhtmlxError.catchError("LoadXML",function(a,b,c){
|
||||
alert(c[0].responseText);
|
||||
});
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
class DelayedConnector extends Connector{
|
||||
protected $init_flag=false;//!< used to prevent rendering while initialization
|
||||
private $data_mode=false;//!< flag to separate xml and data request modes
|
||||
private $data_result=false;//<! store results of query
|
||||
|
||||
public function dataMode($name){
|
||||
$this->data_mode = $name;
|
||||
$this->data_result=array();
|
||||
}
|
||||
public function getDataResult(){
|
||||
return $this->data_result;
|
||||
}
|
||||
|
||||
public function render(){
|
||||
if (!$this->init_flag){
|
||||
$this->init_flag=true;
|
||||
return "";
|
||||
}
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
protected function output_as_xml($res){
|
||||
if ($this->data_mode){
|
||||
while ($data=$this->sql->get_next($res)){
|
||||
$this->data_result[]=$data[$this->data_mode];
|
||||
}
|
||||
}
|
||||
else
|
||||
return parent::output_as_xml($res);
|
||||
}
|
||||
protected function end_run(){
|
||||
if (!$this->data_mode)
|
||||
parent::end_run();
|
||||
}
|
||||
}
|
||||
|
||||
class CrossOptionsConnector extends Connector{
|
||||
public $options, $link;
|
||||
private $master_name, $link_name, $master_value;
|
||||
|
||||
public function __construct($res,$type=false,$item_type=false,$data_type=false){
|
||||
$this->options = new OptionsConnector($res,$type,$item_type,$data_type);
|
||||
$this->link = new DelayedConnector($res,$type,$item_type,$data_type);
|
||||
|
||||
EventMaster::attach_static("connectorInit",array($this, "handle"));
|
||||
}
|
||||
public function handle($conn){
|
||||
if ($conn instanceof DelayedConnector) return;
|
||||
if ($conn instanceof OptionsConnector) return;
|
||||
|
||||
$this->master_name = $this->link->get_config()->id["db_name"];
|
||||
$this->link_name = $this->options->get_config()->id["db_name"];
|
||||
|
||||
$this->link->event->attach("beforeFilter",array($this, "get_only_related"));
|
||||
|
||||
if (isset($_GET["dhx_crosslink_".$this->link_name])){
|
||||
$this->get_links($_GET["dhx_crosslink_".$this->link_name]);
|
||||
die();
|
||||
}
|
||||
|
||||
if (!$this->dload){
|
||||
$conn->event->attach("beforeRender", array($this, "getOptions"));
|
||||
$conn->event->attach("beforeRenderSet", array($this, "prepareConfig"));
|
||||
}
|
||||
|
||||
|
||||
$conn->event->attach("afterProcessing", array($this, "afterProcessing"));
|
||||
}
|
||||
public function prepareConfig($conn, $res, $config){
|
||||
$config->add_field($this->link_name);
|
||||
}
|
||||
public function getOptions($data){
|
||||
$this->link->dataMode($this->link_name);
|
||||
|
||||
$this->get_links($data->get_value($this->master_name));
|
||||
|
||||
$data->set_value($this->link_name, implode(",",$this->link->getDataResult()));
|
||||
}
|
||||
public function get_links($id){
|
||||
$this->master_value = $id;
|
||||
$this->link->render();
|
||||
}
|
||||
public function get_only_related($filters){
|
||||
$index = $filters->index($this->master_name);
|
||||
if ($index!==false){
|
||||
$filters->rules[$index]["value"]=$this->master_value;
|
||||
} else
|
||||
$filters->add($this->master_name, $this->master_value, "=");
|
||||
}
|
||||
public function afterProcessing($action){
|
||||
$status = $action->get_status();
|
||||
|
||||
$master_key = $action->get_value($this->master_name);
|
||||
$link_key = $action->get_value($this->link_name);
|
||||
$link_key = explode(',', $link_key);
|
||||
|
||||
if ($status == "inserted")
|
||||
$master_key = $action->get_new_id();
|
||||
|
||||
switch ($status){
|
||||
case "deleted":
|
||||
$this->link->delete($master_key);
|
||||
break;
|
||||
case "updated":
|
||||
$this->link->delete($master_key);
|
||||
case "inserted":
|
||||
for ($i=0; $i < sizeof($link_key); $i++)
|
||||
if ($link_key[$i]!="")
|
||||
$this->link->insert(array(
|
||||
$this->link_name => $link_key[$i],
|
||||
$this->master_name => $master_key
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,465 @@
|
|||
<?php
|
||||
/*! Base DataProcessor handling
|
||||
**/
|
||||
class DataProcessor{
|
||||
protected $connector;//!< Connector instance
|
||||
protected $config;//!< DataConfig instance
|
||||
protected $request;//!< DataRequestConfig instance
|
||||
|
||||
/*! constructor
|
||||
|
||||
@param connector
|
||||
Connector object
|
||||
@param config
|
||||
DataConfig object
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
*/
|
||||
function __construct($connector,$config,$request){
|
||||
$this->connector= $connector;
|
||||
$this->config=$config;
|
||||
$this->request=$request;
|
||||
}
|
||||
|
||||
/*! convert incoming data name to valid db name
|
||||
redirect to Connector->name_data by default
|
||||
@param data
|
||||
data name from incoming request
|
||||
@return
|
||||
related db_name
|
||||
*/
|
||||
function name_data($data){
|
||||
return $data;
|
||||
}
|
||||
/*! retrieve data from incoming request and normalize it
|
||||
|
||||
@param ids
|
||||
array of extected IDs
|
||||
@return
|
||||
hash of data
|
||||
*/
|
||||
function get_post_values($ids){
|
||||
$data=array();
|
||||
for ($i=0; $i < sizeof($ids); $i++)
|
||||
$data[$ids[$i]]=array();
|
||||
|
||||
foreach ($_POST as $key => $value) {
|
||||
$details=explode("_",$key,2);
|
||||
if (sizeof($details)==1) continue;
|
||||
|
||||
$name=$this->name_data($details[1]);
|
||||
$data[$details[0]][$name]=$value;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
/*! process incoming request ( save|update|delete )
|
||||
*/
|
||||
function process(){
|
||||
LogMaster::log("DataProcessor object initialized",$_POST);
|
||||
|
||||
$results=array();
|
||||
|
||||
if (!isset($_POST["ids"]))
|
||||
throw new Exception("Incorrect incoming data, ID of incoming records not recognized");
|
||||
|
||||
$ids=explode(",",$_POST["ids"]);
|
||||
$rows_data=$this->get_post_values($ids);
|
||||
$failed=false;
|
||||
|
||||
try{
|
||||
if ($this->connector->sql->is_global_transaction())
|
||||
$this->connector->sql->begin_transaction();
|
||||
|
||||
for ($i=0; $i < sizeof($ids); $i++) {
|
||||
$rid = $ids[$i];
|
||||
LogMaster::log("Row data [{$rid}]",$rows_data[$rid]);
|
||||
|
||||
if (!isset($_POST[$rid."_!nativeeditor_status"]))
|
||||
throw new Exception("Status of record [{$rid}] not found in incoming request");
|
||||
$status = $_POST[$rid."_!nativeeditor_status"];
|
||||
|
||||
$action=new DataAction($status,$rid,$rows_data[$rid]);
|
||||
$results[]=$action;
|
||||
$this->inner_process($action);
|
||||
}
|
||||
|
||||
} catch(Exception $e){
|
||||
$failed=true;
|
||||
}
|
||||
|
||||
if ($this->connector->sql->is_global_transaction()){
|
||||
if (!$failed)
|
||||
for ($i=0; $i < sizeof($results); $i++)
|
||||
if ($results[$i]->get_status()=="error" || $results[$i]->get_status()=="invalid"){
|
||||
$failed=true;
|
||||
break;
|
||||
}
|
||||
if ($failed){
|
||||
for ($i=0; $i < sizeof($results); $i++)
|
||||
$results[$i]->error();
|
||||
$this->connector->sql->rollback_transaction();
|
||||
}
|
||||
else
|
||||
$this->connector->sql->commit_transaction();
|
||||
}
|
||||
|
||||
$this->output_as_xml($results);
|
||||
}
|
||||
|
||||
/*! converts status string to the inner mode name
|
||||
|
||||
@param status
|
||||
external status string
|
||||
@return
|
||||
inner mode name
|
||||
*/
|
||||
protected function status_to_mode($status){
|
||||
switch($status){
|
||||
case "updated":
|
||||
return "update";
|
||||
break;
|
||||
case "inserted":
|
||||
return "insert";
|
||||
break;
|
||||
case "deleted":
|
||||
return "delete";
|
||||
break;
|
||||
default:
|
||||
return $status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*! process data updated request received
|
||||
|
||||
@param action
|
||||
DataAction object
|
||||
@return
|
||||
DataAction object with details of processing
|
||||
*/
|
||||
protected function inner_process($action){
|
||||
|
||||
if ($this->connector->sql->is_record_transaction())
|
||||
$this->connector->sql->begin_transaction();
|
||||
|
||||
try{
|
||||
|
||||
$mode = $this->status_to_mode($action->get_status());
|
||||
if (!$this->connector->access->check($mode)){
|
||||
LogMaster::log("Access control: {$operation} operation blocked");
|
||||
$action->error();
|
||||
} else {
|
||||
$check = $this->connector->event->trigger("beforeProcessing",$action);
|
||||
if (!$action->is_ready())
|
||||
$this->check_exts($action,$mode);
|
||||
$check = $this->connector->event->trigger("afterProcessing",$action);
|
||||
}
|
||||
|
||||
} catch (Exception $e){
|
||||
$action->set_status("error");
|
||||
}
|
||||
|
||||
if ($this->connector->sql->is_record_transaction()){
|
||||
if ($action->get_status()=="error" || $action->get_status()=="invalid")
|
||||
$this->connector->sql->rollback_transaction();
|
||||
else
|
||||
$this->connector->sql->commit_transaction();
|
||||
}
|
||||
|
||||
return $action;
|
||||
}
|
||||
/*! check if some event intercepts processing, send data to DataWrapper in other case
|
||||
|
||||
@param action
|
||||
DataAction object
|
||||
@param mode
|
||||
name of inner mode ( will be used to generate event names )
|
||||
*/
|
||||
function check_exts($action,$mode){
|
||||
$old_config = new DataConfig($this->config);
|
||||
|
||||
$this->connector->event->trigger("before".$mode,$action);
|
||||
if ($action->is_ready())
|
||||
LogMaster::log("Event code for ".$mode." processed");
|
||||
else {
|
||||
//check if custom sql defined
|
||||
$sql = $this->connector->sql->get_sql($mode,$action);
|
||||
if ($sql)
|
||||
$this->connector->sql->query($sql);
|
||||
else{
|
||||
$action->sync_config($this->config);
|
||||
$method=array($this->connector->sql,$mode);
|
||||
if (!is_callable($method))
|
||||
throw new Exception("Unknown dataprocessing action: ".$mode);
|
||||
call_user_func($method,$action,$this->request);
|
||||
}
|
||||
}
|
||||
$this->connector->event->trigger("after".$mode,$action);
|
||||
|
||||
$this->config = $old_config;
|
||||
}
|
||||
|
||||
/*! output xml response for dataprocessor
|
||||
|
||||
@param results
|
||||
array of DataAction objects
|
||||
*/
|
||||
function output_as_xml($results){
|
||||
LogMaster::log("Edit operation finished",$results);
|
||||
ob_clean();
|
||||
header("Content-type:text/xml");
|
||||
echo "<?xml version='1.0' ?>";
|
||||
echo "<data>";
|
||||
for ($i=0; $i < sizeof($results); $i++)
|
||||
echo $results[$i]->to_xml();
|
||||
echo "</data>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*! contain all info related to action and controls customizaton
|
||||
**/
|
||||
class DataAction{
|
||||
private $status; //!< cuurent status of record
|
||||
private $id;//!< id of record
|
||||
private $data;//!< data hash of record
|
||||
private $userdata;//!< hash of extra data , attached to record
|
||||
private $nid;//!< new id value , after operation executed
|
||||
private $output;//!< custom output to client side code
|
||||
private $attrs;//!< hash of custtom attributes
|
||||
private $ready;//!< flag of operation's execution
|
||||
private $addf;//!< array of added fields
|
||||
private $delf;//!< array of deleted fields
|
||||
|
||||
|
||||
/*! constructor
|
||||
|
||||
@param status
|
||||
current operation status
|
||||
@param id
|
||||
record id
|
||||
@param data
|
||||
hash of data
|
||||
*/
|
||||
function __construct($status,$id,$data){
|
||||
$this->status=$status;
|
||||
$this->id=$id;
|
||||
$this->data=$data;
|
||||
$this->nid=$id;
|
||||
|
||||
$this->output="";
|
||||
$this->attrs=array();
|
||||
$this->ready=false;
|
||||
|
||||
$this->addf=array();
|
||||
$this->delf=array();
|
||||
}
|
||||
|
||||
|
||||
/*! add custom field and value to DB operation
|
||||
|
||||
@param name
|
||||
name of field which will be added to DB operation
|
||||
@param value
|
||||
value which will be used for related field in DB operation
|
||||
*/
|
||||
function add_field($name,$value){
|
||||
LogMaster::log("adding field: ".$name.", with value: ".$value);
|
||||
$this->data[$name]=$value;
|
||||
$this->addf[]=$name;
|
||||
}
|
||||
/*! remove field from DB operation
|
||||
|
||||
@param name
|
||||
name of field which will be removed from DB operation
|
||||
*/
|
||||
function remove_field($name){
|
||||
LogMaster::log("removing field: ".$name);
|
||||
$this->delf[]=$name;
|
||||
}
|
||||
|
||||
/*! sync field configuration with external object
|
||||
|
||||
@param slave
|
||||
SQLMaster object
|
||||
@todo
|
||||
check , if all fields removed then cancel action
|
||||
*/
|
||||
function sync_config($slave){
|
||||
foreach ($this->addf as $k => $v)
|
||||
$slave->add_field($v);
|
||||
foreach ($this->delf as $k => $v)
|
||||
$slave->remove_field($v);
|
||||
}
|
||||
/*! get value of some record's propery
|
||||
|
||||
@param name
|
||||
name of record's property ( name of db field or alias )
|
||||
@return
|
||||
value of related property
|
||||
*/
|
||||
function get_value($name){
|
||||
if (!array_key_exists($name,$this->data)){
|
||||
LogMaster::log("Incorrect field name used: ".$name);
|
||||
LogMaster::log("data",$this->data);
|
||||
return "";
|
||||
}
|
||||
return $this->data[$name];
|
||||
}
|
||||
/*! set value of some record's propery
|
||||
|
||||
@param name
|
||||
name of record's property ( name of db field or alias )
|
||||
@param value
|
||||
value of related property
|
||||
*/
|
||||
function set_value($name,$value){
|
||||
LogMaster::log("change value of: ".$name." as: ".$value);
|
||||
$this->data[$name]=$value;
|
||||
}
|
||||
/*! get hash of data properties
|
||||
|
||||
@return
|
||||
hash of data properties
|
||||
*/
|
||||
function get_data(){
|
||||
return $this->data;
|
||||
}
|
||||
/*! get some extra info attached to record
|
||||
deprecated, exists just for backward compatibility, you can use set_value instead of it
|
||||
@param name
|
||||
name of userdata property
|
||||
@return
|
||||
value of related userdata property
|
||||
*/
|
||||
function get_userdata_value($name){
|
||||
return $this->get_value($name);
|
||||
}
|
||||
/*! set some extra info attached to record
|
||||
deprecated, exists just for backward compatibility, you can use get_value instead of it
|
||||
@param name
|
||||
name of userdata property
|
||||
@param value
|
||||
value of userdata property
|
||||
*/
|
||||
function set_userdata_value($name,$value){
|
||||
return $this->set_value($name,$value);
|
||||
}
|
||||
/*! get current status of record
|
||||
|
||||
@return
|
||||
string with status value
|
||||
*/
|
||||
function get_status(){
|
||||
return $this->status;
|
||||
}
|
||||
/*! assign new status to the record
|
||||
|
||||
@param status
|
||||
new status value
|
||||
*/
|
||||
function set_status($status){
|
||||
$this->status=$status;
|
||||
}
|
||||
/*! get id of current record
|
||||
|
||||
@return
|
||||
id of record
|
||||
*/
|
||||
function get_id(){
|
||||
return $this->id;
|
||||
}
|
||||
/*! sets custom response text
|
||||
|
||||
can be accessed through defineAction on client side. Text wrapped in CDATA, so no extra escaping necessary
|
||||
@param text
|
||||
custom response text
|
||||
*/
|
||||
function set_response_text($text){
|
||||
$this->set_response_xml("<![CDATA[".$text."]]>");
|
||||
}
|
||||
/*! sets custom response xml
|
||||
|
||||
can be accessed through defineAction on client side
|
||||
@param text
|
||||
string with XML data
|
||||
*/
|
||||
function set_response_xml($text){
|
||||
$this->output=$text;
|
||||
}
|
||||
/*! sets custom response attributes
|
||||
|
||||
can be accessed through defineAction on client side
|
||||
@param name
|
||||
name of custom attribute
|
||||
@param value
|
||||
value of custom attribute
|
||||
*/
|
||||
function set_response_attribute($name,$value){
|
||||
$this->attrs[$name]=$value;
|
||||
}
|
||||
/*! check if action finished
|
||||
|
||||
@return
|
||||
true if action finished, false otherwise
|
||||
*/
|
||||
function is_ready(){
|
||||
return $this->ready;
|
||||
}
|
||||
/*! return new id value
|
||||
|
||||
equal to original ID normally, after insert operation - value assigned for new DB record
|
||||
@return
|
||||
new id value
|
||||
*/
|
||||
function get_new_id(){
|
||||
return $this->nid;
|
||||
}
|
||||
|
||||
/*! set result of operation as error
|
||||
*/
|
||||
function error(){
|
||||
$this->status="error";
|
||||
$this->ready=true;
|
||||
}
|
||||
/*! set result of operation as invalid
|
||||
*/
|
||||
function invalid(){
|
||||
$this->status="invalid";
|
||||
$this->ready=true;
|
||||
}
|
||||
/*! confirm successful opeation execution
|
||||
@param id
|
||||
new id value, optional
|
||||
*/
|
||||
function success($id=false){
|
||||
if ($id!==false)
|
||||
$this->nid = $id;
|
||||
$this->ready=true;
|
||||
}
|
||||
/*! convert DataAction to xml format compatible with client side dataProcessor
|
||||
@return
|
||||
DataAction operation report as XML string
|
||||
*/
|
||||
function to_xml(){
|
||||
$str="<action type='{$this->status}' sid='{$this->id}' tid='{$this->nid}' ";
|
||||
foreach ($this->attrs as $k => $v) {
|
||||
$str.=$k."='".$v."' ";
|
||||
}
|
||||
$str.=">{$this->output}</action>";
|
||||
return $str;
|
||||
}
|
||||
/*! convert self to string ( for logs )
|
||||
|
||||
@return
|
||||
DataAction operation report as plain string
|
||||
*/
|
||||
function __toString(){
|
||||
return "action:{$this->status}; sid:{$this->id}; tid:{$this->nid};";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -0,0 +1,959 @@
|
|||
<?php
|
||||
require_once("tools.php");
|
||||
|
||||
/*! manager of data request
|
||||
**/
|
||||
class DataRequestConfig{
|
||||
private $filters; //!< array of filtering rules
|
||||
private $relation=false; //!< ID or other element used for linking hierarchy
|
||||
private $sort_by; //!< sorting field
|
||||
private $start; //!< start of requested data
|
||||
private $count; //!< length of requested data
|
||||
|
||||
private $user;
|
||||
private $version;
|
||||
|
||||
//for render_sql
|
||||
private $source; //!< souce table or another source destination
|
||||
private $fieldset; //!< set of data, which need to be retrieved from source
|
||||
|
||||
/*! constructor
|
||||
|
||||
@param proto
|
||||
DataRequestConfig object, optional, if provided then new request object will copy all properties from provided one
|
||||
*/
|
||||
public function __construct($proto=false){
|
||||
if ($proto)
|
||||
$this->copy($proto);
|
||||
else{
|
||||
$start=0;
|
||||
$this->filters=array();
|
||||
$this->sort_by=array();
|
||||
}
|
||||
}
|
||||
|
||||
/*! copy parameters of source object into self
|
||||
|
||||
@param proto
|
||||
source object
|
||||
*/
|
||||
public function copy($proto){
|
||||
$this->filters =$proto->get_filters();
|
||||
$this->sort_by =$proto->get_sort_by();
|
||||
$this->count =$proto->get_count();
|
||||
$this->start =$proto->get_start();
|
||||
$this->source =$proto->get_source();
|
||||
$this->fieldset =$proto->get_fieldset();
|
||||
$this->relation =$proto->get_relation();
|
||||
$this->user = $proto->user;
|
||||
$this->version = $proto->version;
|
||||
}
|
||||
|
||||
/*! convert self to string ( for logs )
|
||||
@return
|
||||
self as plain string,
|
||||
*/
|
||||
public function __toString(){
|
||||
$str="Source:{$this->source}\nFieldset:{$this->fieldset}\nWhere:";
|
||||
for ($i=0; $i < sizeof($this->filters); $i++)
|
||||
$str.=$this->filters[$i]["name"]." ".$this->filters[$i]["operation"]." ".$this->filters[$i]["value"].";";
|
||||
$str.="\nStart:{$this->start}\nCount:{$this->count}\n";
|
||||
for ($i=0; $i < sizeof($this->sort_by); $i++)
|
||||
$str.=$this->sort_by[$i]["name"]."=".$this->sort_by[$i]["direction"].";";
|
||||
$str.="\nRelation:{$this->relation}";
|
||||
return $str;
|
||||
}
|
||||
|
||||
/*! returns set of filtering rules
|
||||
@return
|
||||
set of filtering rules
|
||||
*/
|
||||
public function get_filters(){
|
||||
return $this->filters;
|
||||
}
|
||||
public function &get_filters_ref(){
|
||||
return $this->filters;
|
||||
}
|
||||
public function set_filters($data){
|
||||
$this->filters=$data;
|
||||
}
|
||||
|
||||
|
||||
public function get_user(){
|
||||
return $this->user;
|
||||
}
|
||||
public function set_user($user){
|
||||
$this->user = $user;
|
||||
}
|
||||
public function get_version(){
|
||||
return $this->version;
|
||||
}
|
||||
public function set_version($version){
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
/*! returns list of used fields
|
||||
@return
|
||||
list of used fields
|
||||
*/
|
||||
public function get_fieldset(){
|
||||
return $this->fieldset;
|
||||
}
|
||||
/*! returns name of source table
|
||||
@return
|
||||
name of source table
|
||||
*/
|
||||
public function get_source(){
|
||||
return $this->source;
|
||||
}
|
||||
/*! returns set of sorting rules
|
||||
@return
|
||||
set of sorting rules
|
||||
*/
|
||||
public function get_sort_by(){
|
||||
return $this->sort_by;
|
||||
}
|
||||
public function &get_sort_by_ref(){
|
||||
return $this->sort_by;
|
||||
}
|
||||
public function set_sort_by($data){
|
||||
$this->sort_by=$data;
|
||||
}
|
||||
|
||||
/*! returns start index
|
||||
@return
|
||||
start index
|
||||
*/
|
||||
public function get_start(){
|
||||
return $this->start;
|
||||
}
|
||||
/*! returns count of requested records
|
||||
@return
|
||||
count of requested records
|
||||
*/
|
||||
public function get_count(){
|
||||
return $this->count;
|
||||
}
|
||||
/*! returns name of relation id
|
||||
@return
|
||||
relation id name
|
||||
*/
|
||||
public function get_relation(){
|
||||
return $this->relation;
|
||||
}
|
||||
|
||||
/*! sets sorting rule
|
||||
|
||||
@param field
|
||||
name of column
|
||||
@param order
|
||||
direction of sorting
|
||||
*/
|
||||
public function set_sort($field,$order=false){
|
||||
if (!$field && !$order)
|
||||
$this->sort_by=array();
|
||||
else{
|
||||
$order=strtolower($order)=="asc"?"ASC":"DESC";
|
||||
$this->sort_by[]=array("name"=>$field,"direction" => $order);
|
||||
}
|
||||
}
|
||||
/*! sets filtering rule
|
||||
|
||||
@param field
|
||||
name of column
|
||||
@param value
|
||||
value for filtering
|
||||
@param operation
|
||||
operation for filtering, optional , LIKE by default
|
||||
*/
|
||||
public function set_filter($field,$value,$operation=false){
|
||||
array_push($this->filters,array("name"=>$field,"value"=>$value,"operation"=>$operation));
|
||||
}
|
||||
|
||||
/*! sets list of used fields
|
||||
|
||||
@param value
|
||||
list of used fields
|
||||
*/
|
||||
public function set_fieldset($value){
|
||||
$this->fieldset=$value;
|
||||
}
|
||||
/*! sets name of source table
|
||||
|
||||
@param value
|
||||
name of source table
|
||||
*/
|
||||
public function set_source($value){
|
||||
$this->source=trim($value);
|
||||
if (!$this->source) throw new Exception("Source of data can't be empty");
|
||||
}
|
||||
/*! sets data limits
|
||||
|
||||
@param start
|
||||
start index
|
||||
@param count
|
||||
requested count of data
|
||||
*/
|
||||
public function set_limit($start,$count){
|
||||
$this->start=$start;
|
||||
$this->count=$count;
|
||||
}
|
||||
/*! sets name of relation id
|
||||
|
||||
@param value
|
||||
name of relation id field
|
||||
*/
|
||||
public function set_relation($value){
|
||||
$this->relation=$value;
|
||||
}
|
||||
/*! parse incoming sql, to fill other properties
|
||||
|
||||
@param sql
|
||||
incoming sql string
|
||||
*/
|
||||
public function parse_sql($sql){
|
||||
$sql= preg_replace("/[ \n\t]+limit[\n ,0-9]/i","",$sql);
|
||||
|
||||
$data = preg_split("/[ \n\t]+\\_from\\_/i",$sql,2);
|
||||
if (count($data)!=2)
|
||||
$data = preg_split("/[ \n\t]+from/i",$sql,2);
|
||||
$this->fieldset = preg_replace("/^[\s]*select/i","",$data[0],1);
|
||||
|
||||
$table_data = preg_split("/[ \n\t]+where/i",$data[1],2);
|
||||
if (sizeof($table_data)>1){ //where construction exists
|
||||
$this->set_source($table_data[0]);
|
||||
$where_data = preg_split("/[ \n\t]+order[ ]+by/i",$table_data[1],2);
|
||||
$this->filters[]=$where_data[0];
|
||||
if (sizeof($where_data)==1) return; //end of line detected
|
||||
$data=$where_data[1];
|
||||
} else {
|
||||
$table_data = preg_split("/[ \n\t]+order[ ]+by/i",$table_data[0],2);
|
||||
$this->set_source($table_data[0]);
|
||||
if (sizeof($table_data)==1) return; //end of line detected
|
||||
$data=$table_data[1];
|
||||
}
|
||||
|
||||
if (trim($data)){ //order by construction exists
|
||||
$s_data = preg_split("/\\,/",trim($data));
|
||||
for ($i=0; $i < count($s_data); $i++) {
|
||||
$data=preg_split("/[ ]+/",trim($s_data[$i]),2);
|
||||
$this->set_sort($data[0],$data[1]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! manager of data configuration
|
||||
**/
|
||||
class DataConfig{
|
||||
public $id;////!< name of ID field
|
||||
public $relation_id;//!< name or relation ID field
|
||||
public $text;//!< array of text fields
|
||||
public $data;//!< array of all known fields , fields which exists only in this collection will not be included in dataprocessor's operations
|
||||
|
||||
|
||||
/*! converts self to the string, for logging purposes
|
||||
**/
|
||||
public function __toString(){
|
||||
$str="ID:{$this->id['db_name']}(ID:{$this->id['name']})\n";
|
||||
$str.="Relation ID:{$this->relation_id['db_name']}({$this->relation_id['name']})\n";
|
||||
$str.="Data:";
|
||||
for ($i=0; $i<sizeof($this->text); $i++)
|
||||
$str.="{$this->text[$i]['db_name']}({$this->text[$i]['name']}),";
|
||||
|
||||
$str.="\nExtra:";
|
||||
for ($i=0; $i<sizeof($this->data); $i++)
|
||||
$str.="{$this->data[$i]['db_name']}({$this->data[$i]['name']}),";
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/*! removes un-used fields from configuration
|
||||
@param name
|
||||
name of field , which need to be preserved
|
||||
*/
|
||||
public function minimize($name){
|
||||
for ($i=0; $i < sizeof($this->text); $i++){
|
||||
if ($this->text[$i]["name"]==$name){
|
||||
$this->text[$i]["name"]="value";
|
||||
$this->data=array($this->text[$i]);
|
||||
$this->text=array($this->text[$i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Exception("Incorrect dataset minimization, master field not found.");
|
||||
}
|
||||
|
||||
public function limit_fields($data){
|
||||
if (isset($this->full_field_list))
|
||||
$this->restore_fields();
|
||||
$this->full_field_list = $this->text;
|
||||
$this->text = array();
|
||||
|
||||
for ($i=0; $i < sizeof($this->full_field_list); $i++) {
|
||||
if (array_key_exists($this->full_field_list[$i]["name"],$data))
|
||||
$this->text[] = $this->full_field_list[$i];
|
||||
}
|
||||
}
|
||||
|
||||
public function restore_fields(){
|
||||
if (isset($this->full_field_list))
|
||||
$this->text = $this->full_field_list;
|
||||
}
|
||||
|
||||
/*! initialize inner state by parsing configuration parameters
|
||||
|
||||
@param id
|
||||
name of id field
|
||||
@param fields
|
||||
name of data field(s)
|
||||
@param extra
|
||||
name of extra field(s)
|
||||
@param relation
|
||||
name of relation field
|
||||
|
||||
*/
|
||||
public function init($id,$fields,$extra,$relation){
|
||||
$this->id = $this->parse($id,false);
|
||||
$this->text = $this->parse($fields,true);
|
||||
$this->data = array_merge($this->text,$this->parse($extra,true));
|
||||
$this->relation_id = $this->parse($relation,false);
|
||||
}
|
||||
|
||||
/*! parse configuration string
|
||||
|
||||
@param key
|
||||
key string from configuration
|
||||
@param mode
|
||||
multi names flag
|
||||
@return
|
||||
parsed field name object
|
||||
*/
|
||||
private function parse($key,$mode){
|
||||
if ($mode){
|
||||
if (!$key) return array();
|
||||
$key=explode(",",$key);
|
||||
for ($i=0; $i < sizeof($key); $i++)
|
||||
$key[$i]=$this->parse($key[$i],false);
|
||||
return $key;
|
||||
}
|
||||
$key=explode("(",$key);
|
||||
$data=array("db_name"=>trim($key[0]), "name"=>trim($key[0]));
|
||||
if (sizeof($key)>1)
|
||||
$data["name"]=substr(trim($key[1]),0,-1);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*! constructor
|
||||
init public collectons
|
||||
@param proto
|
||||
DataConfig object used as prototype for new one, optional
|
||||
*/
|
||||
public function __construct($proto=false){
|
||||
if ($proto!==false)
|
||||
$this->copy($proto);
|
||||
else {
|
||||
$this->text=array();
|
||||
$this->data=array();
|
||||
$this->id=array("name"=>"dhx_auto_id", "db_name"=>"dhx_auto_id");
|
||||
$this->relation_id=array("name"=>"", "db_name"=>"");
|
||||
}
|
||||
}
|
||||
|
||||
/*! copy properties from source object
|
||||
|
||||
@param proto
|
||||
source object
|
||||
*/
|
||||
public function copy($proto){
|
||||
$this->id = $proto->id;
|
||||
$this->relation_id = $proto->relation_id;
|
||||
$this->text = $proto->text;
|
||||
$this->data = $proto->data;
|
||||
}
|
||||
|
||||
/*! returns list of data fields (db_names)
|
||||
@return
|
||||
list of data fields ( ready to be used in SQL query )
|
||||
*/
|
||||
public function db_names_list($db){
|
||||
$out=array();
|
||||
if ($this->id["db_name"])
|
||||
array_push($out,$db->escape_name($this->id["db_name"]));
|
||||
if ($this->relation_id["db_name"])
|
||||
array_push($out,$db->escape_name($this->relation_id["db_name"]));
|
||||
|
||||
for ($i=0; $i < sizeof($this->data); $i++){
|
||||
if ($this->data[$i]["db_name"]!=$this->data[$i]["name"])
|
||||
$out[]=$db->escape_name($this->data[$i]["db_name"])." as ".$this->data[$i]["name"];
|
||||
else
|
||||
$out[]=$db->escape_name($this->data[$i]["db_name"]);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/*! add field to dataset config ($text collection)
|
||||
|
||||
added field will be used in all auto-generated queries
|
||||
@param name
|
||||
name of field
|
||||
@param aliase
|
||||
aliase of field, optional
|
||||
*/
|
||||
public function add_field($name,$aliase=false){
|
||||
if ($aliase===false) $aliase=$name;
|
||||
|
||||
//adding to list of data-active fields
|
||||
if ($this->id["db_name"]==$name || $this->relation_id["db_name"] == $name){
|
||||
LogMaster::log("Field name already used as ID, be sure that it is really necessary.");
|
||||
}
|
||||
if ($this->is_field($name,$this->text)!=-1)
|
||||
throw new Exception('Data field already registered: '.$name);
|
||||
array_push($this->text,array("db_name"=>$name,"name"=>$aliase));
|
||||
|
||||
//adding to list of all fields as well
|
||||
if ($this->is_field($name,$this->data)==-1)
|
||||
array_push($this->data,array("db_name"=>$name,"name"=>$aliase));
|
||||
|
||||
}
|
||||
|
||||
/*! remove field from dataset config ($text collection)
|
||||
|
||||
removed field will be excluded from all auto-generated queries
|
||||
@param name
|
||||
name of field, or aliase of field
|
||||
*/
|
||||
public function remove_field($name){
|
||||
$ind = $this->is_field($name);
|
||||
if ($ind==-1) throw new Exception('There was no such data field registered as: '.$name);
|
||||
array_splice($this->text,$ind,1);
|
||||
//we not deleting field from $data collection, so it will not be included in data operation, but its data still available
|
||||
}
|
||||
|
||||
/*! check if field is a part of dataset
|
||||
|
||||
@param name
|
||||
name of field
|
||||
@param collection
|
||||
collection, against which check will be done, $text collection by default
|
||||
@return
|
||||
returns true if field already a part of dataset, otherwise returns true
|
||||
*/
|
||||
private function is_field($name,$collection = false){
|
||||
if (!$collection)
|
||||
$collection=$this->text;
|
||||
|
||||
for ($i=0; $i<sizeof($collection); $i++)
|
||||
if ($collection[$i]["name"] == $name || $collection[$i]["db_name"] == $name) return $i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*! Base abstraction class, used for data operations
|
||||
Class abstract access to data, it is a base class to all DB wrappers
|
||||
**/
|
||||
abstract class DataWrapper{
|
||||
protected $connection;
|
||||
protected $config;//!< DataConfig instance
|
||||
/*! constructor
|
||||
@param connection
|
||||
DB connection
|
||||
@param config
|
||||
DataConfig instance
|
||||
*/
|
||||
public function __construct($connection,$config){
|
||||
$this->config=$config;
|
||||
$this->connection=$connection;
|
||||
}
|
||||
|
||||
/*! insert record in storage
|
||||
|
||||
@param data
|
||||
DataAction object
|
||||
@param source
|
||||
DataRequestConfig object
|
||||
*/
|
||||
abstract function insert($data,$source);
|
||||
|
||||
/*! delete record from storage
|
||||
|
||||
@param data
|
||||
DataAction object
|
||||
@param source
|
||||
DataRequestConfig object
|
||||
*/
|
||||
abstract function delete($data,$source);
|
||||
|
||||
/*! update record in storage
|
||||
|
||||
@param data
|
||||
DataAction object
|
||||
@param source
|
||||
DataRequestConfig object
|
||||
*/
|
||||
abstract function update($data,$source);
|
||||
|
||||
/*! select record from storage
|
||||
|
||||
@param source
|
||||
DataRequestConfig object
|
||||
*/
|
||||
abstract function select($source);
|
||||
|
||||
/*! get size of storage
|
||||
|
||||
@param source
|
||||
DataRequestConfig object
|
||||
*/
|
||||
abstract function get_size($source);
|
||||
|
||||
/*! get all variations of field in storage
|
||||
|
||||
@param name
|
||||
name of field
|
||||
@param source
|
||||
DataRequestConfig object
|
||||
*/
|
||||
abstract function get_variants($name,$source);
|
||||
|
||||
/*! checks if there is a custom sql string for specified db operation
|
||||
|
||||
@param name
|
||||
name of DB operation
|
||||
@param data
|
||||
hash of data
|
||||
@return
|
||||
sql string
|
||||
*/
|
||||
public function get_sql($name,$data){
|
||||
return ""; //custom sql not supported by default
|
||||
}
|
||||
|
||||
/*! begins DB transaction
|
||||
*/
|
||||
public function begin_transaction(){
|
||||
throw new Exception("Data wrapper not supports transactions.");
|
||||
}
|
||||
/*! commits DB transaction
|
||||
*/
|
||||
public function commit_transaction(){
|
||||
throw new Exception("Data wrapper not supports transactions.");
|
||||
}
|
||||
/*! rollbacks DB transaction
|
||||
*/
|
||||
public function rollback_transaction(){
|
||||
throw new Exception("Data wrapper not supports transactions.");
|
||||
}
|
||||
}
|
||||
|
||||
/*! Common database abstraction class
|
||||
Class provides base set of methods to access and change data in DB, class used as a base for DB-specific wrappers
|
||||
**/
|
||||
abstract class DBDataWrapper extends DataWrapper{
|
||||
private $transaction = false; //!< type of transaction
|
||||
private $sequence=false;//!< sequence name
|
||||
private $sqls = array();//!< predefined sql actions
|
||||
|
||||
|
||||
/*! assign named sql query
|
||||
@param name
|
||||
name of sql query
|
||||
@param data
|
||||
sql query text
|
||||
*/
|
||||
public function attach($name,$data){
|
||||
$name=strtolower($name);
|
||||
$this->sqls[$name]=$data;
|
||||
}
|
||||
/*! replace vars in sql string with actual values
|
||||
|
||||
@param matches
|
||||
array of field name matches
|
||||
@return
|
||||
value for the var name
|
||||
*/
|
||||
public function get_sql_callback($matches){
|
||||
return $this->escape($this->temp->get_value($matches[1]));
|
||||
}
|
||||
public function get_sql($name,$data){
|
||||
$name=strtolower($name);
|
||||
if (!array_key_exists($name,$this->sqls)) return "";
|
||||
|
||||
|
||||
$str = $this->sqls[$name];
|
||||
$this->temp = $data; //dirty
|
||||
$str = preg_replace_callback('|\{([^}]+)\}|',array($this,"get_sql_callback"),$str);
|
||||
unset ($this->temp); //dirty
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function insert($data,$source){
|
||||
$sql=$this->insert_query($data,$source);
|
||||
$this->query($sql);
|
||||
$data->success($this->get_new_id());
|
||||
}
|
||||
public function delete($data,$source){
|
||||
$sql=$this->delete_query($data,$source);
|
||||
$this->query($sql);
|
||||
$data->success();
|
||||
}
|
||||
public function update($data,$source){
|
||||
$sql=$this->update_query($data,$source);
|
||||
$this->query($sql);
|
||||
$data->success();
|
||||
}
|
||||
public function select($source){
|
||||
$select=$source->get_fieldset();
|
||||
if (!$select){
|
||||
$select=$this->config->db_names_list($this);
|
||||
$select = implode(",",$select);
|
||||
}
|
||||
|
||||
$where=$this->build_where($source->get_filters(),$source->get_relation());
|
||||
$sort=$this->build_order($source->get_sort_by());
|
||||
|
||||
return $this->query($this->select_query($select,$source->get_source(),$where,$sort,$source->get_start(),$source->get_count()));
|
||||
}
|
||||
public function get_size($source){
|
||||
$count = new DataRequestConfig($source);
|
||||
|
||||
$count->set_fieldset("COUNT(*) as DHX_COUNT ");
|
||||
$count->set_sort(null);
|
||||
$count->set_limit(0,0);
|
||||
|
||||
$res=$this->select($count);
|
||||
$data=$this->get_next($res);
|
||||
if (array_key_exists("DHX_COUNT",$data)) return $data["DHX_COUNT"];
|
||||
else return $data["dhx_count"]; //postgresql
|
||||
}
|
||||
public function get_variants($name,$source){
|
||||
$count = new DataRequestConfig($source);
|
||||
$count->set_fieldset("DISTINCT ".$this->escape_name($name)." as value");
|
||||
$count->set_sort(null);
|
||||
$count->set_limit(0,0);
|
||||
|
||||
return $this->select($count);
|
||||
}
|
||||
|
||||
public function sequence($sec){
|
||||
$this->sequence=$sec;
|
||||
}
|
||||
|
||||
|
||||
/*! create an sql string for filtering rules
|
||||
|
||||
@param rules
|
||||
set of filtering rules
|
||||
@param relation
|
||||
name of relation id field
|
||||
@return
|
||||
sql string with filtering rules
|
||||
*/
|
||||
protected function build_where($rules,$relation=false){
|
||||
$sql=array();
|
||||
for ($i=0; $i < sizeof($rules); $i++)
|
||||
if (is_string($rules[$i]))
|
||||
array_push($sql,$rules[$i]);
|
||||
else
|
||||
if ($rules[$i]["value"]!=""){
|
||||
if (!$rules[$i]["operation"])
|
||||
array_push($sql,$this->escape_name($rules[$i]["name"])." LIKE '%".$this->escape($rules[$i]["value"])."%'");
|
||||
else
|
||||
array_push($sql,$this->escape_name($rules[$i]["name"])." ".$rules[$i]["operation"]." '".$this->escape($rules[$i]["value"])."'");
|
||||
}
|
||||
if ($relation!==false)
|
||||
array_push($sql,$this->escape_name($this->config->relation_id["db_name"])." = '".$this->escape($relation)."'");
|
||||
return implode(" AND ",$sql);
|
||||
}
|
||||
/*! convert sorting rules to sql string
|
||||
|
||||
@param by
|
||||
set of sorting rules
|
||||
@return
|
||||
sql string for set of sorting rules
|
||||
*/
|
||||
protected function build_order($by){
|
||||
if (!sizeof($by)) return "";
|
||||
$out = array();
|
||||
for ($i=0; $i < sizeof($by); $i++)
|
||||
if ($by[$i]["name"])
|
||||
$out[]=$this->escape_name($by[$i]["name"])." ".$by[$i]["direction"];
|
||||
return implode(",",$out);
|
||||
}
|
||||
|
||||
/*! generates sql code for select operation
|
||||
|
||||
@param select
|
||||
list of fields in select
|
||||
@param from
|
||||
table name
|
||||
@param where
|
||||
list of filtering rules
|
||||
@param sort
|
||||
list of sorting rules
|
||||
@param start
|
||||
start index of fetching
|
||||
@param count
|
||||
count of records to fetch
|
||||
@return
|
||||
sql string for select operation
|
||||
*/
|
||||
protected function select_query($select,$from,$where,$sort,$start,$count){
|
||||
$sql="SELECT ".$select." FROM ".$from;
|
||||
if ($where) $sql.=" WHERE ".$where;
|
||||
if ($sort) $sql.=" ORDER BY ".$sort;
|
||||
if ($start || $count) $sql.=" LIMIT ".$start.",".$count;
|
||||
return $sql;
|
||||
}
|
||||
/*! generates update sql
|
||||
|
||||
@param data
|
||||
DataAction object
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
@return
|
||||
sql string, which updates record with provided data
|
||||
*/
|
||||
protected function update_query($data,$request){
|
||||
$sql="UPDATE ".$request->get_source()." SET ";
|
||||
$temp=array();
|
||||
for ($i=0; $i < sizeof($this->config->text); $i++) {
|
||||
$step=$this->config->text[$i];
|
||||
|
||||
if ($data->get_value($step["name"])===Null)
|
||||
$step_value ="Null";
|
||||
else
|
||||
$step_value = "'".$this->escape($data->get_value($step["name"]))."'";
|
||||
$temp[$i]= $this->escape_name($step["db_name"])."=". $step_value;
|
||||
}
|
||||
if ($relation = $this->config->relation_id["db_name"]){
|
||||
$temp[]= $this->escape_name($relation)."='".$this->escape($data->get_value($relation))."'";
|
||||
}
|
||||
$sql.=implode(",",$temp)." WHERE ".$this->escape_name($this->config->id["db_name"])."='".$this->escape($data->get_id())."'";
|
||||
|
||||
//if we have limited set - set constraints
|
||||
$where=$this->build_where($request->get_filters(),$request->get_relation());
|
||||
if ($where) $sql.=" AND (".$where.")";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/*! generates delete sql
|
||||
|
||||
@param data
|
||||
DataAction object
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
@return
|
||||
sql string, which delete record
|
||||
*/
|
||||
protected function delete_query($data,$request){
|
||||
$sql="DELETE FROM ".$request->get_source();
|
||||
$sql.=" WHERE ".$this->escape_name($this->config->id["db_name"])."='".$this->escape($data->get_id())."'";
|
||||
|
||||
//if we have limited set - set constraints
|
||||
$where=$this->build_where($request->get_filters(),$request->get_relation());
|
||||
if ($where) $sql.=" AND (".$where.")";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/*! generates insert sql
|
||||
|
||||
@param data
|
||||
DataAction object
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
@return
|
||||
sql string, which inserts new record with provided data
|
||||
*/
|
||||
protected function insert_query($data,$request){
|
||||
$temp_n=array();
|
||||
$temp_v=array();
|
||||
foreach($this->config->text as $k => $v){
|
||||
$temp_n[$k]=$this->escape_name($v["db_name"]);
|
||||
if ($data->get_value($v["name"])===Null)
|
||||
$temp_v[$k]="Null";
|
||||
else
|
||||
$temp_v[$k]="'".$this->escape($data->get_value($v["name"]))."'";
|
||||
}
|
||||
if ($relation = $this->config->relation_id["db_name"]){
|
||||
$temp_n[]=$this->escape_name($relation);
|
||||
$temp_v[]="'".$this->escape($data->get_value($relation))."'";
|
||||
}
|
||||
if ($this->sequence){
|
||||
$temp_n[]=$this->escape_name($this->config->id["db_name"]);
|
||||
$temp_v[]=$this->sequence;
|
||||
}
|
||||
|
||||
$sql="INSERT INTO ".$request->get_source()."(".implode(",",$temp_n).") VALUES (".implode(",",$temp_v).")";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/*! sets the transaction mode, used by dataprocessor
|
||||
|
||||
@param mode
|
||||
mode name
|
||||
*/
|
||||
public function set_transaction_mode($mode){
|
||||
if ($mode!="none" && $mode!="global" && $mode!="record")
|
||||
throw new Exception("Unknown transaction mode");
|
||||
$this->transaction=$mode;
|
||||
}
|
||||
/*! returns true if global transaction mode was specified
|
||||
@return
|
||||
true if global transaction mode was specified
|
||||
*/
|
||||
public function is_global_transaction(){
|
||||
return $this->transaction == "global";
|
||||
}
|
||||
/*! returns true if record transaction mode was specified
|
||||
@return
|
||||
true if record transaction mode was specified
|
||||
*/
|
||||
public function is_record_transaction(){
|
||||
return $this->transaction == "record";
|
||||
}
|
||||
|
||||
|
||||
public function begin_transaction(){
|
||||
$this->query("BEGIN");
|
||||
}
|
||||
public function commit_transaction(){
|
||||
$this->query("COMMIT");
|
||||
}
|
||||
public function rollback_transaction(){
|
||||
$this->query("ROLLBACK");
|
||||
}
|
||||
|
||||
/*! exec sql string
|
||||
|
||||
@param sql
|
||||
sql string
|
||||
@return
|
||||
sql result set
|
||||
*/
|
||||
abstract protected function query($sql);
|
||||
/*! returns next record from result set
|
||||
|
||||
@param res
|
||||
sql result set
|
||||
@return
|
||||
hash of data
|
||||
*/
|
||||
abstract public function get_next($res);
|
||||
/*! returns new id value, for newly inserted row
|
||||
@return
|
||||
new id value, for newly inserted row
|
||||
*/
|
||||
abstract protected function get_new_id();
|
||||
/*! escape data to prevent sql injections
|
||||
@param data
|
||||
unescaped data
|
||||
@return
|
||||
escaped data
|
||||
*/
|
||||
abstract public function escape($data);
|
||||
|
||||
/*! escape field name to prevent sql reserved words conflict
|
||||
@param data
|
||||
unescaped data
|
||||
@return
|
||||
escaped data
|
||||
*/
|
||||
public function escape_name($data){
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*! get list of tables in the database
|
||||
|
||||
@return
|
||||
array of table names
|
||||
*/
|
||||
public function tables_list() {
|
||||
throw new Exception("Not implemented");
|
||||
}
|
||||
|
||||
/*! returns list of fields for the table in question
|
||||
|
||||
@param table
|
||||
name of table in question
|
||||
@return
|
||||
array of field names
|
||||
*/
|
||||
public function fields_list($table) {
|
||||
throw new Exception("Not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
/*! Implementation of DataWrapper for MySQL
|
||||
**/
|
||||
class MySQLDBDataWrapper extends DBDataWrapper{
|
||||
protected $last_result;
|
||||
public function query($sql){
|
||||
LogMaster::log($sql);
|
||||
$res=mysql_query($sql,$this->connection);
|
||||
if ($res===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection));
|
||||
$this->last_result = $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function get_next($res){
|
||||
if (!$res)
|
||||
$res = $this->last_result;
|
||||
|
||||
return mysql_fetch_assoc($res);
|
||||
}
|
||||
|
||||
protected function get_new_id(){
|
||||
return mysql_insert_id($this->connection);
|
||||
}
|
||||
|
||||
public function escape($data){
|
||||
return mysql_real_escape_string($data);
|
||||
}
|
||||
|
||||
public function tables_list() {
|
||||
$result = mysql_query("SHOW TABLES");
|
||||
if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection));
|
||||
|
||||
$tables = array();
|
||||
while ($table = mysql_fetch_array($result)) {
|
||||
$tables[] = $table[0];
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
|
||||
public function fields_list($table) {
|
||||
$result = mysql_query("SHOW COLUMNS FROM `".$table."`");
|
||||
if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection));
|
||||
|
||||
$fields = array();
|
||||
$id = "";
|
||||
while ($field = mysql_fetch_assoc($result)) {
|
||||
if ($field['Key'] == "PRI")
|
||||
$id = $field["Field"];
|
||||
else
|
||||
$fields[] = $field["Field"];
|
||||
}
|
||||
return array("fields" => $fields, "key" => $id );
|
||||
}
|
||||
|
||||
/*! escape field name to prevent sql reserved words conflict
|
||||
@param data
|
||||
unescaped data
|
||||
@return
|
||||
escaped data
|
||||
*/
|
||||
public function escape_name($data){
|
||||
if ((strpos($data,"`")!==false || intval($data)==$data) || (strpos($data,".")!==false))
|
||||
return $data;
|
||||
return '`'.$data.'`';
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
require_once("db_common.php");
|
||||
/*! MSSQL implementation of DataWrapper
|
||||
**/
|
||||
class MsSQLDBDataWrapper extends DBDataWrapper{
|
||||
private $last_id=""; //!< ID of previously inserted record
|
||||
private $insert_operation=false; //!< flag of insert operation
|
||||
private $start_from=false; //!< index of start position
|
||||
|
||||
public function query($sql){
|
||||
LogMaster::log($sql);
|
||||
$res = mssql_query($sql,$this->connection);
|
||||
if ($this->insert_operation){
|
||||
$last = mssql_fetch_assoc($res);
|
||||
$this->last_id = $last["dhx_id"];
|
||||
mssql_free_result($res);
|
||||
}
|
||||
if ($this->start_from)
|
||||
mssql_data_seek($res,$this->start_from);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function get_next($res){
|
||||
return mssql_fetch_assoc($res);
|
||||
}
|
||||
|
||||
protected function get_new_id(){
|
||||
/*
|
||||
MSSQL doesn't support identity or auto-increment fields
|
||||
Insert SQL returns new ID value, which stored in last_id field
|
||||
*/
|
||||
return $this->last_id;
|
||||
}
|
||||
|
||||
protected function insert_query($data,$request){
|
||||
$sql = parent::insert_query($data,$request);
|
||||
$this->insert_operation=true;
|
||||
return $sql.";SELECT @@IDENTITY AS dhx_id";
|
||||
}
|
||||
|
||||
protected function select_query($select,$from,$where,$sort,$start,$count){
|
||||
$sql="SELECT " ;
|
||||
if ($count)
|
||||
$sql.=" TOP ".($count+$start);
|
||||
$sql.=" ".$select." FROM ".$from;
|
||||
if ($where) $sql.=" WHERE ".$where;
|
||||
if ($sort) $sql.=" ORDER BY ".$sort;
|
||||
if ($start && $count)
|
||||
$this->start_from=$start;
|
||||
else
|
||||
$this->start_from=false;
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function escape($data){
|
||||
/*
|
||||
there is no special escaping method for mssql - use common logic
|
||||
*/
|
||||
return str_replace("'","''",$data);
|
||||
}
|
||||
|
||||
public function begin_transaction(){
|
||||
$this->query("BEGIN TRAN");
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
require_once("db_common.php");
|
||||
|
||||
class MySQLiDBDataWrapper extends MySQLDBDataWrapper{
|
||||
|
||||
public function query($sql){
|
||||
LogMaster::log($sql);
|
||||
$res = $this->connection->query($sql);
|
||||
if ($res===false) throw new Exception("MySQL operation failed\n".$this->connection->error);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function get_next($res){
|
||||
return $res->fetch_assoc();
|
||||
}
|
||||
|
||||
protected function get_new_id(){
|
||||
return $this->connection->insert_id;
|
||||
}
|
||||
|
||||
public function escape($data){
|
||||
return $this->connection->real_escape_string($data);
|
||||
}
|
||||
|
||||
public function tables_list() {
|
||||
$result = $this->connection->query("SHOW TABLES");
|
||||
if ($result===false) throw new Exception("MySQL operation failed\n".$this->connection->error);
|
||||
|
||||
$tables = array();
|
||||
while ($table = $result->fetch_array()) {
|
||||
$tables[] = $table[0];
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
|
||||
public function fields_list($table) {
|
||||
$result = $this->connection->query("SHOW COLUMNS FROM `".$table."`");
|
||||
if ($result===false) throw new Exception("MySQL operation failed\n".$this->connection->error);
|
||||
$fields = array();
|
||||
while ($field = $result->fetch_array()) {
|
||||
if ($field['Key'] == "PRI") {
|
||||
$fields[$field[0]] = 1;
|
||||
} else {
|
||||
$fields[$field[0]] = 0;
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
require_once("db_common.php");
|
||||
/*! Implementation of DataWrapper for Oracle
|
||||
**/
|
||||
class OracleDBDataWrapper extends DBDataWrapper{
|
||||
private $last_id=""; //id of previously inserted record
|
||||
private $insert_operation=false; //flag of insert operation
|
||||
|
||||
public function query($sql){
|
||||
LogMaster::log($sql);
|
||||
$stm = oci_parse($this->connection,$sql);
|
||||
if ($stm===false) throw new Exception("Oracle - sql parsing failed\n".oci_error($this->connection));
|
||||
|
||||
$out = array(0=>null);
|
||||
if($this->insert_operation){
|
||||
oci_bind_by_name($stm,":outID",$out[0],999);
|
||||
$this->insert_operation=false;
|
||||
}
|
||||
|
||||
|
||||
$mode = ($this->is_record_transaction() || $this->is_global_transaction())?OCI_DEFAULT:OCI_COMMIT_ON_SUCCESS;
|
||||
$res=oci_execute($stm,$mode);
|
||||
if ($res===false) throw new Exception("Oracle - sql execution failed\n".oci_error($this->connection));
|
||||
|
||||
$this->last_id=$out[0];
|
||||
|
||||
return $stm;
|
||||
}
|
||||
|
||||
public function get_next($res){
|
||||
$data = oci_fetch_assoc($res);
|
||||
if (array_key_exists("VALUE",$data))
|
||||
$data["value"]=$data["VALUE"];
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function get_new_id(){
|
||||
/*
|
||||
Oracle doesn't support identity or auto-increment fields
|
||||
Insert SQL returns new ID value, which stored in last_id field
|
||||
*/
|
||||
return $this->last_id;
|
||||
}
|
||||
|
||||
protected function insert_query($data,$request){
|
||||
$sql = parent::insert_query($data,$request);
|
||||
$this->insert_operation=true;
|
||||
return $sql." returning ".$this->config->id["db_name"]." into :outID";
|
||||
}
|
||||
|
||||
protected function select_query($select,$from,$where,$sort,$start,$count){
|
||||
$sql="SELECT ".$select." FROM ".$from;
|
||||
if ($where) $sql.=" WHERE ".$where;
|
||||
if ($sort) $sql.=" ORDER BY ".$sort;
|
||||
if ($start || $count)
|
||||
$sql="SELECT * FROM ( select /*+ FIRST_ROWS(".$count.")*/dhx_table.*, ROWNUM rnum FROM (".$sql.") dhx_table where ROWNUM <= ".($count+$start)." ) where rnum >".$start;
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function escape($data){
|
||||
/*
|
||||
as far as I can see the only way to escape data is by using oci_bind_by_name
|
||||
while it is neat solution in common case, it conflicts with existing SQL building logic
|
||||
fallback to simple escaping
|
||||
*/
|
||||
return str_replace("'","''",$data);
|
||||
}
|
||||
|
||||
public function begin_transaction(){
|
||||
//auto-start of transaction
|
||||
}
|
||||
public function commit_transaction(){
|
||||
oci_commit($this->connection);
|
||||
}
|
||||
public function rollback_transaction(){
|
||||
oci_rollback($this->connection);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
require_once("db_common.php");
|
||||
/*! Implementation of DataWrapper for PDO
|
||||
|
||||
if you plan to use it for Oracle - use Oracle connection type instead
|
||||
**/
|
||||
class PDODBDataWrapper extends DBDataWrapper{
|
||||
private $last_result;//!< store result or last operation
|
||||
|
||||
public function query($sql){
|
||||
LogMaster::log($sql);
|
||||
|
||||
$res=$this->connection->query($sql);
|
||||
if ($res===false) throw new Exception("PDO - sql execution failed\n".$this->connection->errorInfo());
|
||||
|
||||
return new PDOResultSet($res);
|
||||
}
|
||||
|
||||
protected function select_query($select,$from,$where,$sort,$start,$count){
|
||||
$sql="SELECT ".$select." FROM ".$from;
|
||||
if ($where) $sql.=" WHERE ".$where;
|
||||
if ($sort) $sql.=" ORDER BY ".$sort;
|
||||
if ($start || $count) {
|
||||
if ($this->connection->getAttribute(PDO::ATTR_DRIVER_NAME)=="pgsql")
|
||||
$sql.=" OFFSET ".$start." LIMIT ".$count;
|
||||
else
|
||||
$sql.=" LIMIT ".$start.",".$count;
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
public function get_next($res){
|
||||
$data = $res->next();
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function get_new_id(){
|
||||
return $this->connection->lastInsertId();
|
||||
}
|
||||
|
||||
public function escape($str){
|
||||
$res=$this->connection->quote($str);
|
||||
if ($res===false) //not supported by pdo driver
|
||||
return str_replace("'","''",$str);
|
||||
return substr($res,1,-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PDOResultSet{
|
||||
private $res;
|
||||
public function __construct($res){
|
||||
$this->res = $res;
|
||||
}
|
||||
public function next(){
|
||||
$data = $this->res->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$data){
|
||||
$this->res->closeCursor();
|
||||
return null;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
require_once("db_common.php");
|
||||
/*! Implementation of DataWrapper for PostgreSQL
|
||||
**/
|
||||
class PostgreDBDataWrapper extends DBDataWrapper{
|
||||
public function query($sql){
|
||||
LogMaster::log($sql);
|
||||
|
||||
$res=pg_query($this->connection,$sql);
|
||||
if ($res===false) throw new Exception("Postgre - sql execution failed\n".pg_last_error($this->connection));
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function select_query($select,$from,$where,$sort,$start,$count){
|
||||
$sql="SELECT ".$select." FROM ".$from;
|
||||
if ($where) $sql.=" WHERE ".$where;
|
||||
if ($sort) $sql.=" ORDER BY ".$sort;
|
||||
if ($start || $count)
|
||||
$sql.=" OFFSET ".$start." LIMIT ".$count;
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function get_next($res){
|
||||
return pg_fetch_assoc($res);
|
||||
}
|
||||
|
||||
protected function get_new_id(){
|
||||
$res = pg_query( $this->connection, "SELECT LASTVAL() AS seq");
|
||||
$data = pg_fetch_assoc($res);
|
||||
pg_free_result($res);
|
||||
return $data['seq'];
|
||||
}
|
||||
|
||||
public function escape($data){
|
||||
//need to use oci_bind_by_name
|
||||
return pg_escape_string($this->connection,$data);
|
||||
}
|
||||
|
||||
public function tables_list() {
|
||||
$sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'";
|
||||
$res = pg_query($this->connection, $sql);
|
||||
$tables = array();
|
||||
while ($table = pg_fetch_assoc($res)) {
|
||||
$tables[] = $table['table_name'];
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
|
||||
public function fields_list($table) {
|
||||
$sql = "SELECT * FROM information_schema.constraint_column_usage";
|
||||
$result = pg_query($this->connection, $sql);
|
||||
$field = pg_fetch_assoc($result);
|
||||
$id = $field['column_name'];
|
||||
|
||||
$sql = "SELECT * FROM information_schema.columns WHERE table_name ='".$table."';";
|
||||
$result = pg_query($this->connection, $sql);
|
||||
$fields = array();
|
||||
$id = "";
|
||||
while ($field = pg_fetch_assoc($result)) {
|
||||
$fields[] = $field["column_name"];
|
||||
}
|
||||
return array('fields' => $fields, 'key' => $id );
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,268 @@
|
|||
<?php
|
||||
require_once("base_connector.php");
|
||||
require_once("grid_config.php");
|
||||
|
||||
//require_once("grid_dataprocessor.php");
|
||||
|
||||
/*! DataItem class for Grid component
|
||||
**/
|
||||
|
||||
class GridDataItem extends DataItem{
|
||||
protected $row_attrs;//!< hash of row attributes
|
||||
protected $cell_attrs;//!< hash of cell attributes
|
||||
protected $userdata;
|
||||
|
||||
function __construct($data,$name,$index=0){
|
||||
parent::__construct($data,$name,$index);
|
||||
|
||||
$this->row_attrs=array();
|
||||
$this->cell_attrs=array();
|
||||
$this->userdata=array();
|
||||
}
|
||||
/*! set color of row
|
||||
|
||||
@param color
|
||||
color of row
|
||||
*/
|
||||
function set_row_color($color){
|
||||
$this->row_attrs["bgColor"]=$color;
|
||||
}
|
||||
/*! set style of row
|
||||
|
||||
@param color
|
||||
color of row
|
||||
*/
|
||||
function set_row_style($color){
|
||||
$this->row_attrs["style"]=$color;
|
||||
}
|
||||
/*! assign custom style to the cell
|
||||
|
||||
@param name
|
||||
name of column
|
||||
@param value
|
||||
css style string
|
||||
*/
|
||||
function set_cell_style($name,$value){
|
||||
$this->set_cell_attribute($name,"style",$value);
|
||||
}
|
||||
/*! assign custom class to specific cell
|
||||
|
||||
@param name
|
||||
name of column
|
||||
@param value
|
||||
css class name
|
||||
*/
|
||||
function set_cell_class($name,$value){
|
||||
$this->set_cell_attribute($name,"class",$value);
|
||||
}
|
||||
/*! set custom cell attribute
|
||||
|
||||
@param name
|
||||
name of column
|
||||
@param attr
|
||||
name of attribute
|
||||
@param value
|
||||
value of attribute
|
||||
*/
|
||||
function set_cell_attribute($name,$attr,$value){
|
||||
if (!$this->cell_attrs[$name]) $this->cell_attrs[$name]=array();
|
||||
$this->cell_attrs[$name][$attr]=$value;
|
||||
}
|
||||
|
||||
/*! set userdata section for the item
|
||||
|
||||
@param name
|
||||
name of userdata
|
||||
@param value
|
||||
value of userdata
|
||||
*/
|
||||
function set_userdata($name, $value){
|
||||
$this->userdata[$name]=$value;
|
||||
}
|
||||
|
||||
/*! set custom row attribute
|
||||
|
||||
@param attr
|
||||
name of attribute
|
||||
@param value
|
||||
value of attribute
|
||||
*/
|
||||
function set_row_attribute($attr,$value){
|
||||
$this->row_attrs[$attr]=$value;
|
||||
}
|
||||
|
||||
/*! return self as XML string, starting part
|
||||
*/
|
||||
public function to_xml_start(){
|
||||
if ($this->skip) return "";
|
||||
|
||||
$str="<row id='".$this->get_id()."'";
|
||||
foreach ($this->row_attrs as $k=>$v)
|
||||
$str.=" ".$k."='".$v."'";
|
||||
$str.=">";
|
||||
for ($i=0; $i < sizeof($this->config->text); $i++){
|
||||
$str.="<cell";
|
||||
$name=$this->config->text[$i]["name"];
|
||||
if (isset($this->cell_attrs[$name])){
|
||||
$cattrs=$this->cell_attrs[$name];
|
||||
foreach ($cattrs as $k => $v)
|
||||
$str.=" ".$k."='".$this->xmlentities($v)."'";
|
||||
}
|
||||
$str.="><![CDATA[".$this->data[$name]."]]></cell>";
|
||||
}
|
||||
foreach ($this->userdata as $key => $value)
|
||||
$str.="<userdata name='".$key."'><![CDATA[".$value."]]></userdata>";
|
||||
|
||||
return $str;
|
||||
}
|
||||
/*! return self as XML string, ending part
|
||||
*/
|
||||
public function to_xml_end(){
|
||||
if ($this->skip) return "";
|
||||
|
||||
return "</row>";
|
||||
}
|
||||
}
|
||||
/*! Connector for the dhtmlxgrid
|
||||
**/
|
||||
class GridConnector extends Connector{
|
||||
protected $extra_output="";//!< extra info which need to be sent to client side
|
||||
private $options=array();//!< hash of OptionsConnector
|
||||
|
||||
/*! constructor
|
||||
|
||||
Here initilization of all Masters occurs, execution timer initialized
|
||||
@param res
|
||||
db connection resource
|
||||
@param type
|
||||
string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided
|
||||
@param item_type
|
||||
name of class, which will be used for item rendering, optional, DataItem will be used by default
|
||||
@param data_type
|
||||
name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default.
|
||||
*/
|
||||
public function __construct($res,$type=false,$item_type=false,$data_type=false){
|
||||
if (!$item_type) $item_type="GridDataItem";
|
||||
if (!$data_type) $data_type="GridDataProcessor";
|
||||
parent::__construct($res,$type,$item_type,$data_type);
|
||||
}
|
||||
|
||||
|
||||
protected function parse_request(){
|
||||
parent::parse_request();
|
||||
|
||||
if (isset($_GET["dhx_colls"]))
|
||||
$this->fill_collections($_GET["dhx_colls"]);
|
||||
|
||||
if (isset($_GET["posStart"]) && isset($_GET["count"]))
|
||||
$this->request->set_limit($_GET["posStart"],$_GET["count"]);
|
||||
}
|
||||
protected function resolve_parameter($name){
|
||||
if (intval($name).""==$name)
|
||||
return $this->config->text[intval($name)]["db_name"];
|
||||
return $name;
|
||||
}
|
||||
|
||||
/*! replace xml unsafe characters
|
||||
|
||||
@param string
|
||||
string to be escaped
|
||||
@return
|
||||
escaped string
|
||||
*/
|
||||
private function xmlentities($string) {
|
||||
return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string);
|
||||
}
|
||||
|
||||
/*! assign options collection to the column
|
||||
|
||||
@param name
|
||||
name of the column
|
||||
@param options
|
||||
array or connector object
|
||||
*/
|
||||
public function set_options($name,$options){
|
||||
if (is_array($options)){
|
||||
$str="";
|
||||
foreach($options as $k => $v)
|
||||
$str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />";
|
||||
$options=$str;
|
||||
}
|
||||
$this->options[$name]=$options;
|
||||
}
|
||||
/*! generates xml description for options collections
|
||||
|
||||
@param list
|
||||
comma separated list of column names, for which options need to be generated
|
||||
*/
|
||||
protected function fill_collections($list){
|
||||
$names=explode(",",$list);
|
||||
for ($i=0; $i < sizeof($names); $i++) {
|
||||
$name = $this->resolve_parameter($names[$i]);
|
||||
if (!array_key_exists($name,$this->options)){
|
||||
$this->options[$name] = new DistinctOptionsConnector($this->get_connection(),$this->names["db_class"]);
|
||||
$c = new DataConfig($this->config);
|
||||
$r = new DataRequestConfig($this->request);
|
||||
$c->minimize($name);
|
||||
|
||||
$this->options[$name]->render_connector($c,$r);
|
||||
}
|
||||
|
||||
$this->extra_output.="<coll_options for='{$names[$i]}'>";
|
||||
if (!is_string($this->options[$name]))
|
||||
$this->extra_output.=$this->options[$name]->render();
|
||||
else
|
||||
$this->extra_output.=$this->options[$name];
|
||||
$this->extra_output.="</coll_options>";
|
||||
}
|
||||
}
|
||||
|
||||
/*! renders self as xml, starting part
|
||||
*/
|
||||
protected function xml_start(){
|
||||
if ($this->dload){
|
||||
if ($pos=$this->request->get_start())
|
||||
return "<rows pos='".$pos."'>";
|
||||
else
|
||||
return "<rows total_count='".$this->sql->get_size($this->request)."'>";
|
||||
}
|
||||
else
|
||||
return "<rows>";
|
||||
}
|
||||
|
||||
|
||||
/*! renders self as xml, ending part
|
||||
*/
|
||||
protected function xml_end(){
|
||||
return $this->extra_output."</rows>";
|
||||
}
|
||||
|
||||
public function set_config($config = false){
|
||||
if (gettype($config) == 'boolean')
|
||||
$config = new GridConfiguration($config);
|
||||
|
||||
$this->event->attach("beforeOutput", Array($config, "attachHeaderToXML"));
|
||||
}
|
||||
}
|
||||
|
||||
/*! DataProcessor class for Grid component
|
||||
**/
|
||||
class GridDataProcessor extends DataProcessor{
|
||||
|
||||
/*! convert incoming data name to valid db name
|
||||
converts c0..cN to valid field names
|
||||
@param data
|
||||
data name from incoming request
|
||||
@return
|
||||
related db_name
|
||||
*/
|
||||
function name_data($data){
|
||||
if ($data == "gr_id") return $this->config->id["name"];
|
||||
$parts=explode("c",$data);
|
||||
if ($parts[0]=="" && intval($parts[1])==$parts[1])
|
||||
return $this->config->text[intval($parts[1])]["name"];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
require_once("base_connector.php");
|
||||
|
||||
/*! DataItem class for Scheduler component
|
||||
**/
|
||||
class SchedulerDataItem extends DataItem{
|
||||
/*! return self as XML string
|
||||
*/
|
||||
function to_xml(){
|
||||
if ($this->skip) return "";
|
||||
|
||||
$str="<event id='".$this->get_id()."' >";
|
||||
$str.="<start_date><![CDATA[".$this->data[$this->config->text[0]["name"]]."]]></start_date>";
|
||||
$str.="<end_date><![CDATA[".$this->data[$this->config->text[1]["name"]]."]]></end_date>";
|
||||
$str.="<text><![CDATA[".$this->data[$this->config->text[2]["name"]]."]]></text>";
|
||||
for ($i=3; $i<sizeof($this->config->text); $i++){
|
||||
$extra = $this->config->text[$i]["name"];
|
||||
$str.="<".$extra."><![CDATA[".$this->data[$extra]."]]></".$extra.">";
|
||||
}
|
||||
return $str."</event>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Connector class for dhtmlxScheduler
|
||||
**/
|
||||
class SchedulerConnector extends Connector{
|
||||
|
||||
protected $extra_output="";//!< extra info which need to be sent to client side
|
||||
private $options=array();//!< hash of OptionsConnector
|
||||
|
||||
|
||||
/*! assign options collection to the column
|
||||
|
||||
@param name
|
||||
name of the column
|
||||
@param options
|
||||
array or connector object
|
||||
*/
|
||||
public function set_options($name,$options){
|
||||
if (is_array($options)){
|
||||
$str="";
|
||||
foreach($options as $k => $v)
|
||||
$str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />";
|
||||
$options=$str;
|
||||
}
|
||||
$this->options[$name]=$options;
|
||||
}
|
||||
/*! generates xml description for options collections
|
||||
|
||||
@param list
|
||||
comma separated list of column names, for which options need to be generated
|
||||
*/
|
||||
protected function fill_collections(){
|
||||
foreach ($this->options as $k=>$v) {
|
||||
$name = $k;
|
||||
$this->extra_output.="<coll_options for='{$name}'>";
|
||||
if (!is_string($this->options[$name]))
|
||||
$this->extra_output.=$this->options[$name]->render();
|
||||
else
|
||||
$this->extra_output.=$this->options[$name];
|
||||
$this->extra_output.="</coll_options>";
|
||||
}
|
||||
}
|
||||
|
||||
/*! renders self as xml, ending part
|
||||
*/
|
||||
protected function xml_end(){
|
||||
$this->fill_collections();
|
||||
return $this->extra_output."</data>";
|
||||
}
|
||||
|
||||
|
||||
/*! constructor
|
||||
|
||||
Here initilization of all Masters occurs, execution timer initialized
|
||||
@param res
|
||||
db connection resource
|
||||
@param type
|
||||
string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided
|
||||
@param item_type
|
||||
name of class, which will be used for item rendering, optional, DataItem will be used by default
|
||||
@param data_type
|
||||
name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default.
|
||||
*/
|
||||
public function __construct($res,$type=false,$item_type=false,$data_type=false){
|
||||
if (!$item_type) $item_type="SchedulerDataItem";
|
||||
if (!$data_type) $data_type="SchedulerDataProcessor";
|
||||
parent::__construct($res,$type,$item_type,$data_type);
|
||||
}
|
||||
|
||||
//parse GET scoope, all operations with incoming request must be done here
|
||||
function parse_request(){
|
||||
parent::parse_request();
|
||||
if (count($this->config->text)){
|
||||
if (isset($_GET["to"]))
|
||||
$this->request->set_filter($this->config->text[0]["name"],$_GET["to"],"<");
|
||||
if (isset($_GET["from"]))
|
||||
$this->request->set_filter($this->config->text[1]["name"],$_GET["from"],">");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! DataProcessor class for Scheduler component
|
||||
**/
|
||||
class SchedulerDataProcessor extends DataProcessor{
|
||||
function name_data($data){
|
||||
if ($data=="start_date")
|
||||
return $this->config->text[0]["db_name"];
|
||||
if ($data=="id")
|
||||
return $this->config->id["db_name"];
|
||||
if ($data=="end_date")
|
||||
return $this->config->text[1]["db_name"];
|
||||
if ($data=="text")
|
||||
return $this->config->text[2]["db_name"];
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
/*!
|
||||
@file
|
||||
Inner classes, which do common tasks. No one of them is purposed for direct usage.
|
||||
*/
|
||||
|
||||
/*! Class which allows to assign|fire events.
|
||||
*/
|
||||
class EventMaster{
|
||||
private $events;//!< hash of event handlers
|
||||
private static $eventsStatic=array();
|
||||
|
||||
/*! constructor
|
||||
*/
|
||||
function __construct(){
|
||||
$this->events=array();
|
||||
}
|
||||
/*! Method check if event with such name already exists.
|
||||
@param name
|
||||
name of event, case non-sensitive
|
||||
@return
|
||||
true if event with such name registered, false otherwise
|
||||
*/
|
||||
public function exist($name){
|
||||
$name=strtolower($name);
|
||||
return (isset($this->events[$name]) && sizeof($this->events[$name]));
|
||||
}
|
||||
/*! Attach custom code to event.
|
||||
|
||||
Only on event handler can be attached in the same time. If new event handler attached - old will be detached.
|
||||
|
||||
@param name
|
||||
name of event, case non-sensitive
|
||||
@param method
|
||||
function which will be attached. You can use array(class, method) if you want to attach the method of the class.
|
||||
*/
|
||||
public function attach($name,$method){
|
||||
$name=strtolower($name);
|
||||
if (!array_key_exists($name,$this->events))
|
||||
$this->events[$name]=array();
|
||||
$this->events[$name][]=$method;
|
||||
}
|
||||
|
||||
public static function attach_static($name, $method){
|
||||
$name=strtolower($name);
|
||||
if (!array_key_exists($name,EventMaster::$eventsStatic))
|
||||
EventMaster::$eventsStatic[$name]=array();
|
||||
EventMaster::$eventsStatic[$name][]=$method;
|
||||
}
|
||||
|
||||
public static function trigger_static($name, $method){
|
||||
$arg_list = func_get_args();
|
||||
$name=strtolower(array_shift($arg_list));
|
||||
|
||||
if (isset(EventMaster::$eventsStatic[$name]))
|
||||
foreach(EventMaster::$eventsStatic[$name] as $method){
|
||||
if (is_array($method) && !method_exists($method[0],$method[1]))
|
||||
throw new Exception("Incorrect method assigned to event: ".$method[0].":".$method[1]);
|
||||
if (!is_array($method) && !function_exists($method))
|
||||
throw new Exception("Incorrect function assigned to event: ".$method);
|
||||
call_user_func_array($method, $arg_list);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Detach code from event
|
||||
@param name
|
||||
name of event, case non-sensitive
|
||||
*/
|
||||
public function detach($name){
|
||||
$name=strtolower($name);
|
||||
unset($this->events[$name]);
|
||||
}
|
||||
/*! Trigger event.
|
||||
@param name
|
||||
name of event, case non-sensitive
|
||||
@param data
|
||||
value which will be provided as argument for event function,
|
||||
you can provide multiple data arguments, method accepts variable number of parameters
|
||||
@return
|
||||
true if event handler was not assigned , result of event hangler otherwise
|
||||
*/
|
||||
public function trigger($name,$data){
|
||||
$arg_list = func_get_args();
|
||||
$name=strtolower(array_shift($arg_list));
|
||||
|
||||
if (isset($this->events[$name]))
|
||||
foreach($this->events[$name] as $method){
|
||||
if (is_array($method) && !method_exists($method[0],$method[1]))
|
||||
throw new Exception("Incorrect method assigned to event: ".$method[0].":".$method[1]);
|
||||
if (!is_array($method) && !function_exists($method))
|
||||
throw new Exception("Incorrect function assigned to event: ".$method);
|
||||
call_user_func_array($method, $arg_list);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Class which handles access rules.
|
||||
**/
|
||||
class AccessMaster{
|
||||
private $rules,$local;
|
||||
/*! constructor
|
||||
|
||||
Set next access right to "allowed" by default : read, insert, update, delete
|
||||
Basically - all common data operations allowed by default
|
||||
*/
|
||||
function __construct(){
|
||||
$this->rules=array("read" => true, "insert" => true, "update" => true, "delete" => true);
|
||||
$this->local=true;
|
||||
}
|
||||
/*! change access rule to "allow"
|
||||
@param name
|
||||
name of access right
|
||||
*/
|
||||
public function allow($name){
|
||||
$this->rules[$name]=true;
|
||||
}
|
||||
/*! change access rule to "deny"
|
||||
|
||||
@param name
|
||||
name of access right
|
||||
*/
|
||||
public function deny($name){
|
||||
$this->rules[$name]=false;
|
||||
}
|
||||
|
||||
/*! change all access rules to "deny"
|
||||
*/
|
||||
public function deny_all(){
|
||||
$this->rules=array();
|
||||
}
|
||||
|
||||
/*! check access rule
|
||||
|
||||
@param name
|
||||
name of access right
|
||||
@return
|
||||
true if access rule allowed, false otherwise
|
||||
*/
|
||||
public function check($name){
|
||||
if ($this->local){
|
||||
/*!
|
||||
todo
|
||||
add referrer check, to prevent access from remote points
|
||||
*/
|
||||
}
|
||||
if (!isset($this->rules[$name]) || !$this->rules[$name]){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Controls error and debug logging.
|
||||
Class designed to be used as static object.
|
||||
**/
|
||||
class LogMaster{
|
||||
private static $_log=false;//!< logging mode flag
|
||||
private static $_output=false;//!< output error infor to client flag
|
||||
private static $session="";//!< all messages generated for current request
|
||||
|
||||
/*! convert array to string representation ( it is a bit more readable than var_dump )
|
||||
|
||||
@param data
|
||||
data object
|
||||
@param pref
|
||||
prefix string, used for formating, optional
|
||||
@return
|
||||
string with array description
|
||||
*/
|
||||
private static function log_details($data,$pref=""){
|
||||
if (is_array($data)){
|
||||
$str=array("");
|
||||
foreach($data as $k=>$v)
|
||||
array_push($str,$pref.$k." => ".LogMaster::log_details($v,$pref."\t"));
|
||||
return implode("\n",$str);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
/*! put record in log
|
||||
|
||||
@param str
|
||||
string with log info, optional
|
||||
@param data
|
||||
data object, which will be added to log, optional
|
||||
*/
|
||||
public static function log($str="",$data=""){
|
||||
if (LogMaster::$_log){
|
||||
$message = $str.LogMaster::log_details($data)."\n\n";
|
||||
LogMaster::$session.=$message;
|
||||
error_log($message,3,LogMaster::$_log);
|
||||
}
|
||||
}
|
||||
|
||||
/*! get logs for current request
|
||||
@return
|
||||
string, which contains all log messages generated for current request
|
||||
*/
|
||||
public static function get_session_log(){
|
||||
return LogMaster::$session;
|
||||
}
|
||||
|
||||
/*! error handler, put normal php errors in log file
|
||||
|
||||
@param errn
|
||||
error number
|
||||
@param errstr
|
||||
error description
|
||||
@param file
|
||||
error file
|
||||
@param line
|
||||
error line
|
||||
@param context
|
||||
error cntext
|
||||
*/
|
||||
public static function error_log($errn,$errstr,$file,$line,$context){
|
||||
LogMaster::log($errstr." at ".$file." line ".$line);
|
||||
}
|
||||
|
||||
/*! exception handler, used as default reaction on any error - show execution log and stop processing
|
||||
|
||||
@param exception
|
||||
instance of Exception
|
||||
*/
|
||||
public static function exception_log($exception){
|
||||
LogMaster::log("!!!Uncaught Exception\nCode: " . $exception->getCode() . "\nMessage: " . $exception->getMessage());
|
||||
if (LogMaster::$_output){
|
||||
echo "<pre><xmp>\n";
|
||||
echo LogMaster::get_session_log();
|
||||
echo "\n</xmp></pre>";
|
||||
}
|
||||
die();
|
||||
}
|
||||
|
||||
/*! enable logging
|
||||
|
||||
@param name
|
||||
path to the log file, if boolean false provided as value - logging will be disabled
|
||||
@param output
|
||||
flag of client side output, if enabled - session log will be sent to client side in case of an error.
|
||||
*/
|
||||
public static function enable_log($name,$output=false){
|
||||
LogMaster::$_log=$name;
|
||||
LogMaster::$_output=$output;
|
||||
if ($name){
|
||||
set_error_handler(array("LogMaster","error_log"),E_ALL);
|
||||
set_exception_handler(array("LogMaster","exception_log"));
|
||||
LogMaster::log("\n\n====================================\nLog started, ".date("d/m/Y h:m:s")."\n====================================");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,274 @@
|
|||
<?php
|
||||
require_once("base_connector.php");
|
||||
|
||||
/*! DataItem class for Tree component
|
||||
**/
|
||||
|
||||
class TreeDataItem extends DataItem{
|
||||
private $im0;//!< image of closed folder
|
||||
private $im1;//!< image of opened folder
|
||||
private $im2;//!< image of leaf item
|
||||
private $check;//!< checked state
|
||||
private $kids=-1;//!< checked state
|
||||
private $attrs;//!< collection of custom attributes
|
||||
|
||||
function __construct($data,$config,$index){
|
||||
parent::__construct($data,$config,$index);
|
||||
|
||||
$this->im0=false;
|
||||
$this->im1=false;
|
||||
$this->im2=false;
|
||||
$this->check=false;
|
||||
$this->attrs = array();
|
||||
$this->userdata = array();
|
||||
}
|
||||
/*! get id of parent record
|
||||
|
||||
@return
|
||||
id of parent record
|
||||
*/
|
||||
function get_parent_id(){
|
||||
return $this->data[$this->config->relation_id["name"]];
|
||||
}
|
||||
/*! get state of items checkbox
|
||||
|
||||
@return
|
||||
state of item's checkbox as int value, false if state was not defined
|
||||
*/
|
||||
function get_check_state(){
|
||||
return $this->check;
|
||||
}
|
||||
/*! set state of item's checkbox
|
||||
|
||||
@param value
|
||||
int value, 1 - checked, 0 - unchecked, -1 - third state
|
||||
*/
|
||||
function set_check_state($value){
|
||||
$this->check=$value;
|
||||
}
|
||||
|
||||
/*! return count of child items
|
||||
-1 if there is no info about childs
|
||||
@return
|
||||
count of child items
|
||||
*/
|
||||
function has_kids(){
|
||||
return $this->kids;
|
||||
}
|
||||
/*! sets count of child items
|
||||
@param value
|
||||
count of child items
|
||||
*/
|
||||
function set_kids($value){
|
||||
$this->kids=$value;
|
||||
}
|
||||
|
||||
/*! set custom attribute
|
||||
|
||||
@param name
|
||||
name of the attribute
|
||||
@param value
|
||||
new value of the attribute
|
||||
*/
|
||||
function set_attribute($name, $value){
|
||||
switch($name){
|
||||
case "id":
|
||||
$this->set_id($value);
|
||||
break;
|
||||
case "text":
|
||||
$this->data[$this->config->text[0]["name"]]=$value;
|
||||
break;
|
||||
case "checked":
|
||||
$this->set_check_state($value);
|
||||
break;
|
||||
case "im0":
|
||||
$this->im0=$value;
|
||||
break;
|
||||
case "im1":
|
||||
$this->im1=$value;
|
||||
break;
|
||||
case "im2":
|
||||
$this->im2=$value;
|
||||
break;
|
||||
case "child":
|
||||
$this->set_kids($value);
|
||||
break;
|
||||
default:
|
||||
$this->attrs[$name]=$value;
|
||||
}
|
||||
}
|
||||
|
||||
/*! set userdata section for the item
|
||||
|
||||
@param name
|
||||
name of userdata
|
||||
@param value
|
||||
value of userdata
|
||||
*/
|
||||
function set_userdata($name, $value){
|
||||
$this->userdata[$name]=$value;
|
||||
}
|
||||
|
||||
/*! assign image for tree's item
|
||||
|
||||
@param img_folder_closed
|
||||
image for item, which represents folder in closed state
|
||||
@param img_folder_open
|
||||
image for item, which represents folder in opened state, optional
|
||||
@param img_leaf
|
||||
image for item, which represents leaf item, optional
|
||||
*/
|
||||
function set_image($img_folder_closed,$img_folder_open=false,$img_leaf=false){
|
||||
$this->im0=$img_folder_closed;
|
||||
$this->im1=$img_folder_open?$img_folder_open:$img_folder_closed;
|
||||
$this->im2=$img_leaf?$img_leaf:$img_folder_closed;
|
||||
}
|
||||
/*! return self as XML string, starting part
|
||||
*/
|
||||
function to_xml_start(){
|
||||
if ($this->skip) return "";
|
||||
|
||||
$str1="<item id='".$this->get_id()."' text='".$this->xmlentities($this->data[$this->config->text[0]["name"]])."' ";
|
||||
if ($this->has_kids()==true) $str1.="child='".$this->has_kids()."' ";
|
||||
if ($this->im0) $str1.="im0='".$this->im0."' ";
|
||||
if ($this->im1) $str1.="im1='".$this->im0."' ";
|
||||
if ($this->im2) $str1.="im2='".$this->im0."' ";
|
||||
if ($this->check) $str1.="checked='".$this->check."' ";
|
||||
foreach ($this->attrs as $key => $value)
|
||||
$str1.=$key."='".$this->xmlentities($value)."' ";
|
||||
$str1.=">";
|
||||
foreach ($this->userdata as $key => $value)
|
||||
$str1.="<userdata name='".$key."'><![CDATA[".$value."]]></userdata>";
|
||||
|
||||
return $str1;
|
||||
}
|
||||
/*! return self as XML string, ending part
|
||||
*/
|
||||
function to_xml_end(){
|
||||
if ($this->skip) return "";
|
||||
return "</item>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
require_once("filesystem_item.php");
|
||||
|
||||
/*! Connector for the dhtmlxtree
|
||||
**/
|
||||
class TreeConnector extends Connector{
|
||||
private $id_swap = array();
|
||||
|
||||
/*! constructor
|
||||
|
||||
Here initilization of all Masters occurs, execution timer initialized
|
||||
@param res
|
||||
db connection resource
|
||||
@param type
|
||||
string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided
|
||||
@param item_type
|
||||
name of class, which will be used for item rendering, optional, DataItem will be used by default
|
||||
@param data_type
|
||||
name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default.
|
||||
*/
|
||||
public function __construct($res,$type=false,$item_type=false,$data_type=false){
|
||||
if (!$item_type) $item_type="TreeDataItem";
|
||||
if (!$data_type) $data_type="TreeDataProcessor";
|
||||
parent::__construct($res,$type,$item_type,$data_type);
|
||||
|
||||
$this->event->attach("afterInsert",array($this,"parent_id_correction_a"));
|
||||
$this->event->attach("beforeProcessing",array($this,"parent_id_correction_b"));
|
||||
}
|
||||
|
||||
/*! store info about ID changes during insert operation
|
||||
@param dataAction
|
||||
data action object during insert operation
|
||||
*/
|
||||
public function parent_id_correction_a($dataAction){
|
||||
$this->id_swap[$dataAction->get_id()]=$dataAction->get_new_id();
|
||||
}
|
||||
/*! update ID if it was affected by previous operation
|
||||
@param dataAction
|
||||
data action object, before any processing operation
|
||||
*/
|
||||
public function parent_id_correction_b($dataAction){
|
||||
$relation = $this->config->relation_id["db_name"];
|
||||
$value = $dataAction->get_value($relation);
|
||||
|
||||
if (array_key_exists($value,$this->id_swap))
|
||||
$dataAction->set_value($relation,$this->id_swap[$value]);
|
||||
}
|
||||
|
||||
|
||||
public function parse_request(){
|
||||
parent::parse_request();
|
||||
|
||||
if (isset($_GET["id"]))
|
||||
$this->request->set_relation($_GET["id"]);
|
||||
else
|
||||
$this->request->set_relation("0");
|
||||
|
||||
$this->request->set_limit(0,0); //netralize default reaction on dyn. loading mode
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function render_set($res){
|
||||
$output="";
|
||||
$index=0;
|
||||
while ($data=$this->sql->get_next($res)){
|
||||
$data = new $this->names["item_class"]($data,$this->config,$index);
|
||||
$this->event->trigger("beforeRender",$data);
|
||||
//there is no info about child elements,
|
||||
//if we are using dyn. loading - assume that it has,
|
||||
//in normal mode juse exec sub-render routine
|
||||
if ($data->has_kids()===-1 && $this->dload)
|
||||
$data->set_kids(true);
|
||||
$output.=$data->to_xml_start();
|
||||
if ($data->has_kids()===-1 || ( $data->has_kids()==true && !$this->dload)){
|
||||
$sub_request = new DataRequestConfig($this->request);
|
||||
$sub_request->set_relation($data->get_id());
|
||||
$output.=$this->render_set($this->sql->select($sub_request));
|
||||
}
|
||||
$output.=$data->to_xml_end();
|
||||
$index++;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
/*! renders self as xml, starting part
|
||||
*/
|
||||
public function xml_start(){
|
||||
return "<tree id='".$this->request->get_relation()."'>";
|
||||
}
|
||||
|
||||
/*! renders self as xml, ending part
|
||||
*/
|
||||
public function xml_end(){
|
||||
return "</tree>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TreeDataProcessor extends DataProcessor{
|
||||
|
||||
function __construct($connector,$config,$request){
|
||||
parent::__construct($connector,$config,$request);
|
||||
$request->set_relation(false);
|
||||
}
|
||||
|
||||
/*! convert incoming data name to valid db name
|
||||
converts c0..cN to valid field names
|
||||
@param data
|
||||
data name from incoming request
|
||||
@return
|
||||
related db_name
|
||||
*/
|
||||
function name_data($data){
|
||||
if ($data=="tr_pid")
|
||||
return $this->config->relation_id["db_name"];
|
||||
if ($data=="tr_text")
|
||||
return $this->config->text[0]["db_name"];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
require_once("grid_connector.php");
|
||||
|
||||
/*! DataItem class for TreeGrid component
|
||||
**/
|
||||
class TreeGridDataItem extends GridDataItem{
|
||||
private $kids=-1;//!< checked state
|
||||
|
||||
function __construct($data,$config,$index){
|
||||
parent::__construct($data,$config,$index);
|
||||
$this->im0=false;
|
||||
}
|
||||
/*! return id of parent record
|
||||
|
||||
@return
|
||||
id of parent record
|
||||
*/
|
||||
function get_parent_id(){
|
||||
return $this->data[$this->config->relation_id["name"]];
|
||||
}
|
||||
/*! assign image to treegrid's item
|
||||
longer description
|
||||
@param img
|
||||
relative path to the image
|
||||
*/
|
||||
function set_image($img){
|
||||
$this->set_cell_attribute($this->config->text[0]["name"],"image",$img);
|
||||
}
|
||||
|
||||
/*! return count of child items
|
||||
-1 if there is no info about childs
|
||||
@return
|
||||
count of child items
|
||||
*/
|
||||
function has_kids(){
|
||||
return $this->kids;
|
||||
}
|
||||
/*! sets count of child items
|
||||
@param value
|
||||
count of child items
|
||||
*/
|
||||
function set_kids($value){
|
||||
$this->kids=$value;
|
||||
if ($value)
|
||||
$this->set_row_attribute("xmlkids",$value);
|
||||
}
|
||||
}
|
||||
/*! Connector for dhtmlxTreeGrid
|
||||
**/
|
||||
class TreeGridConnector extends GridConnector{
|
||||
private $id_swap = array();
|
||||
|
||||
/*! constructor
|
||||
|
||||
Here initilization of all Masters occurs, execution timer initialized
|
||||
@param res
|
||||
db connection resource
|
||||
@param type
|
||||
string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided
|
||||
@param item_type
|
||||
name of class, which will be used for item rendering, optional, DataItem will be used by default
|
||||
@param data_type
|
||||
name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default.
|
||||
*/
|
||||
public function __construct($res,$type=false,$item_type=false,$data_type=false){
|
||||
if (!$item_type) $item_type="TreeGridDataItem";
|
||||
if (!$data_type) $data_type="TreeGridDataProcessor";
|
||||
parent::__construct($res,$type,$item_type,$data_type);
|
||||
|
||||
$this->event->attach("afterInsert",array($this,"parent_id_correction_a"));
|
||||
$this->event->attach("beforeProcessing",array($this,"parent_id_correction_b"));
|
||||
}
|
||||
|
||||
/*! store info about ID changes during insert operation
|
||||
@param dataAction
|
||||
data action object during insert operation
|
||||
*/
|
||||
public function parent_id_correction_a($dataAction){
|
||||
$this->id_swap[$dataAction->get_id()]=$dataAction->get_new_id();
|
||||
}
|
||||
/*! update ID if it was affected by previous operation
|
||||
@param dataAction
|
||||
data action object, before any processing operation
|
||||
*/
|
||||
public function parent_id_correction_b($dataAction){
|
||||
$relation = $this->config->relation_id["db_name"];
|
||||
$value = $dataAction->get_value($relation);
|
||||
|
||||
if (array_key_exists($value,$this->id_swap))
|
||||
$dataAction->set_value($relation,$this->id_swap[$value]);
|
||||
}
|
||||
|
||||
/*! process treegrid specific options in incoming request
|
||||
*/
|
||||
public function parse_request(){
|
||||
parent::parse_request();
|
||||
|
||||
if (isset($_GET["id"]))
|
||||
$this->request->set_relation($_GET["id"]);
|
||||
else
|
||||
$this->request->set_relation("0");
|
||||
|
||||
$this->request->set_limit(0,0); //netralize default reaction on dyn. loading mode
|
||||
}
|
||||
|
||||
/*! process treegrid specific options in incoming request
|
||||
*/
|
||||
protected function render_set($res){
|
||||
$output="";
|
||||
$index=0;
|
||||
while ($data=$this->sql->get_next($res)){
|
||||
$data = new $this->names["item_class"]($data,$this->config,$index);
|
||||
$this->event->trigger("beforeRender",$data);
|
||||
//there is no info about child elements,
|
||||
//if we are using dyn. loading - assume that it has,
|
||||
//in normal mode juse exec sub-render routine
|
||||
if ($data->has_kids()===-1 && $this->dload)
|
||||
$data->set_kids(true);
|
||||
$output.=$data->to_xml_start();
|
||||
if ($data->has_kids()===-1 || ( $data->has_kids()==true && !$this->dload)){
|
||||
$sub_request = new DataRequestConfig($this->request);
|
||||
$sub_request->set_relation($data->get_id());
|
||||
$output.=$this->render_set($this->sql->select($sub_request));
|
||||
}
|
||||
$output.=$data->to_xml_end();
|
||||
$index++;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/*! renders self as xml, starting part
|
||||
*/
|
||||
protected function xml_start(){
|
||||
return "<rows parent='".$this->request->get_relation()."'>";
|
||||
}
|
||||
}
|
||||
|
||||
/*! DataProcessor class for Grid component
|
||||
**/
|
||||
class TreeGridDataProcessor extends GridDataProcessor{
|
||||
|
||||
function __construct($connector,$config,$request){
|
||||
parent::__construct($connector,$config,$request);
|
||||
$request->set_relation(false);
|
||||
}
|
||||
|
||||
/*! convert incoming data name to valid db name
|
||||
converts c0..cN to valid field names
|
||||
@param data
|
||||
data name from incoming request
|
||||
@return
|
||||
related db_name
|
||||
*/
|
||||
function name_data($data){
|
||||
|
||||
if ($data=="gr_pid")
|
||||
return $this->config->relation_id["name"];
|
||||
else return parent::name_data($data);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,262 @@
|
|||
<?php
|
||||
|
||||
/*! DataItemUpdate class for realization Optimistic concurrency control
|
||||
Wrapper for DataItem object
|
||||
It's used during outputing updates instead of DataItem object
|
||||
Create wrapper for every data item with update information.
|
||||
*/
|
||||
class DataItemUpdate extends DataItem {
|
||||
|
||||
|
||||
/*! constructor
|
||||
@param data
|
||||
hash of data
|
||||
@param config
|
||||
DataConfig object
|
||||
@param index
|
||||
index of element
|
||||
*/
|
||||
public function __construct($data,$config,$index,$type){
|
||||
$this->config=$config;
|
||||
$this->data=$data;
|
||||
$this->index=$index;
|
||||
$this->skip=false;
|
||||
$this->child = new $type($data, $config, $index);
|
||||
}
|
||||
|
||||
/*! returns parent_id (for Tree and TreeGrid components)
|
||||
*/
|
||||
public function get_parent_id(){
|
||||
if (method_exists($this->child, 'get_parent_id')) {
|
||||
return $this->child->get_parent_id();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! generate XML on the data hash base
|
||||
*/
|
||||
public function to_xml(){
|
||||
$str= "<update ";
|
||||
$str .= 'status="'.$this->data['type'].'" ';
|
||||
$str .= 'id="'.$this->data['dataId'].'" ';
|
||||
$str .= 'parent="'.$this->get_parent_id().'"';
|
||||
$str .= '>';
|
||||
$str .= $this->child->to_xml();
|
||||
$str .= '</update>';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/*! return starting tag for XML string
|
||||
*/
|
||||
public function to_xml_start(){
|
||||
$str="<update ";
|
||||
$str .= 'status="'.$this->data['type'].'" ';
|
||||
$str .= 'id="'.$this->data['dataId'].'" ';
|
||||
$str .= 'parent="'.$this->get_parent_id().'"';
|
||||
$str .= '>';
|
||||
$str .= $this->child->to_xml_start();
|
||||
return $str;
|
||||
}
|
||||
|
||||
/*! return ending tag for XML string
|
||||
*/
|
||||
public function to_xml_end(){
|
||||
$str = $this->child->to_xml_end();
|
||||
$str .= '</update>';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/*! returns false for outputing only current item without child items
|
||||
*/
|
||||
public function has_kids(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! sets count of child items
|
||||
@param value
|
||||
count of child items
|
||||
*/
|
||||
public function set_kids($value){
|
||||
if (method_exists($this->child, 'set_kids')) {
|
||||
$this->child->set_kids($value);
|
||||
}
|
||||
}
|
||||
|
||||
/*! sets attribute for item
|
||||
*/
|
||||
public function set_attribute($name, $value){
|
||||
if (method_exists($this->child, 'set_attribute')) {
|
||||
LogMaster::log("setting attribute: \nname = {$name}\nvalue = {$value}");
|
||||
$this->child->set_attribute($name, $value);
|
||||
} else {
|
||||
LogMaster::log("set_attribute method doesn't exists");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DataUpdate{
|
||||
|
||||
protected $table; //!< table , where actions are stored
|
||||
protected $url; //!< url for notification service, optional
|
||||
protected $sql; //!< DB wrapper object
|
||||
protected $config; //!< DBConfig object
|
||||
protected $request; //!< DBRequestConfig object
|
||||
protected $event;
|
||||
protected $item_class;
|
||||
protected $demu;
|
||||
|
||||
//protected $config;//!< DataConfig instance
|
||||
//protected $request;//!< DataRequestConfig instance
|
||||
|
||||
/*! constructor
|
||||
|
||||
@param connector
|
||||
Connector object
|
||||
@param config
|
||||
DataConfig object
|
||||
@param request
|
||||
DataRequestConfig object
|
||||
*/
|
||||
function __construct($sql, $config, $request, $table, $url){
|
||||
$this->config= $config;
|
||||
$this->request= $request;
|
||||
$this->sql = $sql;
|
||||
$this->table=$table;
|
||||
$this->url=$url;
|
||||
$this->demu = false;
|
||||
}
|
||||
|
||||
public function set_demultiplexor($path){
|
||||
$this->demu = $path;
|
||||
}
|
||||
|
||||
public function set_event($master, $name){
|
||||
$this->event = $master;
|
||||
$this->item_class = $name;
|
||||
}
|
||||
|
||||
private function select_update($actions_table, $join_table, $id_field_name, $version, $user) {
|
||||
$sql = "SELECT * FROM {$actions_table}";
|
||||
$sql .= " LEFT OUTER JOIN {$join_table} ON ";
|
||||
$sql .= "{$actions_table}.DATAID = {$join_table}.{$id_field_name} ";
|
||||
$sql .= "WHERE {$actions_table}.ID > '{$version}' AND {$actions_table}.USER <> '{$user}'";
|
||||
return $sql;
|
||||
}
|
||||
|
||||
private function get_update_max_version() {
|
||||
$sql = "SELECT MAX(id) as VERSION FROM {$this->table}";
|
||||
$res = $this->sql->query($sql);
|
||||
$data = $this->sql->get_next($res);
|
||||
|
||||
if ($data == false || $data['VERSION'] == false)
|
||||
return 1;
|
||||
else
|
||||
return $data['VERSION'];
|
||||
}
|
||||
|
||||
private function log_update_action($actions_table, $dataId, $status, $user) {
|
||||
$sql = "INSERT INTO {$actions_table} (DATAID, TYPE, USER) VALUES ('{$dataId}', '{$status}', '{$user}')";
|
||||
$this->sql->query($sql);
|
||||
if ($this->demu)
|
||||
file_get_contents($this->demu);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! records operations in actions_table
|
||||
@param action
|
||||
DataAction object
|
||||
*/
|
||||
public function log_operations($action) {
|
||||
$type = $this->sql->escape($action->get_status());
|
||||
$dataId = $this->sql->escape($action->get_new_id());
|
||||
$user = $this->sql->escape($this->request->get_user());
|
||||
if ($type!="error" && $type!="invalid" && $type !="collision") {
|
||||
$this->log_update_action($this->table, $dataId, $type, $user);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! return action version in XMl format
|
||||
*/
|
||||
public function get_version() {
|
||||
$version = $this->get_update_max_version();
|
||||
return "<userdata name='version'>".$version."</userdata>";
|
||||
}
|
||||
|
||||
|
||||
/*! adds action version in output XML as userdata
|
||||
*/
|
||||
public function version_output() {
|
||||
echo $this->get_version();
|
||||
}
|
||||
|
||||
|
||||
/*! create update actions in XML-format and sends it to output
|
||||
*/
|
||||
public function get_updates() {
|
||||
$sub_request = new DataRequestConfig($this->request);
|
||||
$version = $this->request->get_version();
|
||||
$user = $this->request->get_user();
|
||||
|
||||
$sub_request->parse_sql($this->select_update($this->table, $this->request->get_source(), $this->config->id['db_name'], $version, $user));
|
||||
$sub_request->set_relation(false);
|
||||
|
||||
$output = $this->render_set($this->sql->select($sub_request), $this->item_class);
|
||||
|
||||
ob_clean();
|
||||
header("Content-type:text/xml");
|
||||
|
||||
echo $this->updates_start();
|
||||
echo $this->get_version();
|
||||
echo $output;
|
||||
echo $this->updates_end();
|
||||
}
|
||||
|
||||
|
||||
protected function render_set($res, $name){
|
||||
$output="";
|
||||
$index=0;
|
||||
while ($data=$this->sql->get_next($res)){
|
||||
$data = new DataItemUpdate($data,$this->config,$index, $name);
|
||||
$this->event->trigger("beforeRender",$data);
|
||||
$output.=$data->to_xml();
|
||||
$index++;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/*! returns update start string
|
||||
*/
|
||||
protected function updates_start() {
|
||||
$start = '<updates>';
|
||||
return $start;
|
||||
}
|
||||
|
||||
/*! returns update end string
|
||||
*/
|
||||
protected function updates_end() {
|
||||
$start = '</updates>';
|
||||
return $start;
|
||||
}
|
||||
|
||||
/*! checks if action version given by client is deprecated
|
||||
@param action
|
||||
DataAction object
|
||||
*/
|
||||
public function check_collision($action) {
|
||||
$version = $this->sql->escape($this->request->get_version());
|
||||
//$user = $this->sql->escape($this->request->get_user());
|
||||
$last_version = $this->get_update_max_version();
|
||||
if (($last_version > $version)&&($action->get_status() == 'update')) {
|
||||
$action->error();
|
||||
$action->set_status('collision');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
window.dhx||(dhx={});dhx.version="3.0";dhx.codebase="./";dhx.name="Core";dhx.copy=function(a){var b=dhx.copy.Sd;b.prototype=a;return new b};dhx.copy.Sd=function(){};dhx.extend=function(a,b,c){a.Ya&&(a=a.Ya[0]);for(var d in b)if(!a[d]||c)a[d]=b[d];b.defaults&&dhx.extend(a.defaults,b.defaults);b.$init&&b.$init.call(a);return a};
|
||||
dhx.fullCopy=function(a){var b=a.length?[]:{};arguments.length>1&&(b=arguments[0],a=arguments[1]);for(var c in a)typeof a[c]=="object"?(b[c]=a[c].length?[]:{},dhx.fullCopy(b[c],a[c])):b[c]=a[c];return b};dhx.single=function(a){var b=null,c=function(c){b||(b=new a({}));b.Yc&&b.Yc.apply(b,arguments);return b};return c};
|
||||
dhx.protoUI=function(){var a=arguments,b=a[0].name,c=function(d){if(a){for(var e=[a[0]],f=1;f<a.length;f++)e[f]=a[f],e[f].Ya&&(e[f]=e[f].call(dhx)),e[f].prototype&&e[f].prototype.name&&(dhx.ui[e[f].prototype.name]=e[f]);dhx.ui[b]=dhx.proto.apply(dhx,e);if(c.Ga)for(f=0;f<c.Ga.length;f++)dhx.Type(dhx.ui[b],c.Ga[f]);c=a=null}return this!=dhx?new dhx.ui[b](d):dhx.ui[b]};c.Ya=arguments;return dhx.ui[b]=c};
|
||||
dhx.proto=function(){for(var a=arguments,b=a[0],c=!!b.$init,d=[],e=a.length-1;e>0;e--){if(typeof a[e]=="function")a[e]=a[e].prototype;a[e].$init&&d.push(a[e].$init);if(a[e].defaults){var f=a[e].defaults;if(!b.defaults)b.defaults={};for(var g in f)dhx.isNotDefined(b.defaults[g])&&(b.defaults[g]=f[g])}if(a[e].type&&b.type)for(g in a[e].type)b.type[g]||(b.type[g]=a[e].type[g]);for(var h in a[e])b[h]||(b[h]=a[e][h])}c&&d.push(b.$init);b.$init=function(){for(var a=0;a<d.length;a++)d[a].apply(this,arguments)};
|
||||
var i=function(a){this.$ready=[];this.$init(a);this.Rb&&this.Rb(a,this.defaults);for(var b=0;b<this.$ready.length;b++)this.$ready[b].call(this)};i.prototype=b;b=a=null;return i};dhx.bind=function(a,b){return function(){return a.apply(b,arguments)}};dhx.require=function(a){dhx.Mc[a]||(dhx.exec(dhx.ajax().sync().get(dhx.codebase+a).responseText),dhx.Mc[a]=!0)};dhx.Mc={};dhx.exec=function(a){window.execScript?window.execScript(a):window.eval(a)};
|
||||
dhx.wrap=function(a,b){return!a?b:function(){var c=a.apply(this,arguments);b.apply(this,arguments);return c}};dhx.methodPush=function(a,b){return function(){var c=!1;return c=a[b].apply(a,arguments)}};dhx.isNotDefined=function(a){return typeof a=="undefined"};dhx.delay=function(a,b,c,d){return window.setTimeout(function(){var d=a.apply(b,c||[]);a=b=c=null;return d},d||1)};dhx.uid=function(){if(!this.bc)this.bc=(new Date).valueOf();this.bc++;return this.bc};
|
||||
dhx.toNode=function(a){return typeof a=="string"?document.getElementById(a):a};dhx.toArray=function(a){return dhx.extend(a||[],dhx.PowerArray,!0)};dhx.toFunctor=function(a){return typeof a=="string"?eval(a):a};dhx.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"};dhx.o={};dhx.event=function(a,b,c,d){var a=dhx.toNode(a),e=dhx.uid();d&&(c=dhx.bind(c,d));dhx.o[e]=[a,b,c];a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c);return e};
|
||||
dhx.eventRemove=function(a){if(a){var b=dhx.o[a];b[0].removeEventListener?b[0].removeEventListener(b[1],b[2],!1):b[0].detachEvent&&b[0].detachEvent("on"+b[1],b[2]);delete this.o[a]}};
|
||||
dhx.EventSystem={$init:function(){this.o={};this.ka={};this.Mb={}},blockEvent:function(){this.o.oc=!0},unblockEvent:function(){this.o.oc=!1},mapEvent:function(a){dhx.extend(this.Mb,a,!0)},on_setter:function(a){if(a)for(var b in a)typeof a[b]=="function"&&this.attachEvent(b,a[b])},callEvent:function(a,b){if(this.o.oc)return!0;var a=a.toLowerCase(),c=this.o[a.toLowerCase()],d=!0;if(c)for(var e=0;e<c.length;e++)if(c[e].apply(this,b||[])===!1)d=!1;this.Mb[a]&&!this.Mb[a].callEvent(a,b)&&(d=!1);return d},
|
||||
attachEvent:function(a,b,c){var a=a.toLowerCase(),c=c||dhx.uid(),b=dhx.toFunctor(b),d=this.o[a]||dhx.toArray();d.push(b);this.o[a]=d;this.ka[c]={f:b,t:a};return c},detachEvent:function(a){if(this.ka[a]){var b=this.ka[a].t,c=this.ka[a].f,d=this.o[b];d.remove(c);delete this.ka[a]}},hasEvent:function(a){a=a.toLowerCase();return this.o[a]?!0:!1}};dhx.extend(dhx,dhx.EventSystem);
|
||||
dhx.PowerArray={removeAt:function(a,b){a>=0&&this.splice(a,b||1)},remove:function(a){this.removeAt(this.find(a))},insertAt:function(a,b){if(!b&&b!==0)this.push(a);else{var c=this.splice(b,this.length-b);this[b]=a;this.push.apply(this,c)}},find:function(a){for(var b=0;b<this.length;b++)if(a==this[b])return b;return-1},each:function(a,b){for(var c=0;c<this.length;c++)a.call(b||this,this[c])},map:function(a,b){for(var c=0;c<this.length;c++)this[c]=a.call(b||this,this[c]);return this}};dhx.env={};
|
||||
(function(){if(navigator.userAgent.indexOf("Mobile")!=-1)dhx.env.mobile=!0;if(dhx.env.mobile||navigator.userAgent.indexOf("iPad")!=-1||navigator.userAgent.indexOf("Android")!=-1)dhx.env.touch=!0;navigator.userAgent.indexOf("Opera")!=-1?dhx.env.isOpera=!0:(dhx.env.isIE=!!document.all,dhx.env.isFF=!document.all,dhx.env.isWebKit=navigator.userAgent.indexOf("KHTML")!=-1,dhx.env.isSafari=dhx.env.isWebKit&&navigator.userAgent.indexOf("Mac")!=-1);if(navigator.userAgent.toLowerCase().indexOf("android")!=
|
||||
-1)dhx.env.isAndroid=!0;dhx.env.transform=!1;dhx.env.transition=!1;for(var a={names:["transform","transition"],transform:["transform","WebkitTransform","MozTransform","oTransform","msTransform"],transition:["transition","WebkitTransition","MozTransition","oTransition","msTransition"]},b=document.createElement("DIV"),c=0;c<a.names.length;c++)for(var d=a[a.names[c]],e=0;e<d.length;e++)if(typeof b.style[d[e]]!="undefined"){dhx.env[a.names[c]]=d[e];break}b.style[dhx.env.transform]="translate3d(0,0,0)";
|
||||
dhx.env.translate=b.style[dhx.env.transform]?"translate3d":"translate";dhx.env.transformCSSPrefix=function(){var a;dhx.env.isOpera?a="-o-":(a="",dhx.env.isFF&&(a="-Moz-"),dhx.env.isWebKit&&(a="-webkit-"),dhx.env.isIE&&(a="-ms-"));return a}();dhx.env.transformPrefix=dhx.env.transformCSSPrefix.replace(/-/gi,"");dhx.env.transitionEnd=dhx.env.transformCSSPrefix=="-Moz-"?"transitionend":dhx.env.transformPrefix+"TransitionEnd"})();
|
||||
dhx.env.svg=function(){return document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")}();
|
||||
dhx.html={create:function(a,b,c){var b=b||{},d=document.createElement(a),e;for(e in b)d.setAttribute(e,b[e]);if(b.style)d.style.cssText=b.style;if(b["class"])d.className=b["class"];if(c)d.innerHTML=c;return d},getValue:function(a){a=dhx.toNode(a);return!a?"":dhx.isNotDefined(a.value)?a.innerHTML:a.value},remove:function(a){if(a instanceof Array)for(var b=0;b<a.length;b++)this.remove(a[b]);else a&&a.parentNode&&a.parentNode.removeChild(a)},insertBefore:function(a,b,c){a&&(b&&b.parentNode?b.parentNode.insertBefore(a,
|
||||
b):c.appendChild(a))},locate:function(a,b){if(a.tagName)var c=a;else a=a||event,c=a.target||a.srcElement;for(;c;){if(c.getAttribute){var d=c.getAttribute(b);if(d)return d}c=c.parentNode}return null},offset:function(a){if(a.getBoundingClientRect){var b=a.getBoundingClientRect(),c=document.body,d=document.documentElement,e=window.pageYOffset||d.scrollTop||c.scrollTop,f=window.pageXOffset||d.scrollLeft||c.scrollLeft,g=d.clientTop||c.clientTop||0,h=d.clientLeft||c.clientLeft||0,i=b.top+e-g,j=b.left+f-
|
||||
h;return{y:Math.round(i),x:Math.round(j)}}else{for(j=i=0;a;)i+=parseInt(a.offsetTop,10),j+=parseInt(a.offsetLeft,10),a=a.offsetParent;return{y:i,x:j}}},pos:function(a){a=a||event;if(a.pageX||a.pageY)return{x:a.pageX,y:a.pageY};var b=dhx.env.isIE&&document.compatMode!="BackCompat"?document.documentElement:document.body;return{x:a.clientX+b.scrollLeft-b.clientLeft,y:a.clientY+b.scrollTop-b.clientTop}},preventEvent:function(a){a&&a.preventDefault&&a.preventDefault();return dhx.html.stopEvent(a)},stopEvent:function(a){(a||
|
||||
event).cancelBubble=!0;return!1},addCss:function(a,b){a.className+=" "+b},removeCss:function(a,b){a.className=a.className.replace(RegExp(" "+b,"g"),"")}};dhx.ready=function(a){this.ze?a.call():this.ob.push(a)};dhx.ob=[];
|
||||
(function(){var a=document.getElementsByTagName("SCRIPT");if(a.length)a=(a[a.length-1].getAttribute("src")||"").split("/"),a.splice(a.length-1,1),dhx.codebase=a.slice(0,a.length).join("/")+"/";dhx.event(window,"load",function(){dhx.callEvent("onReady",[]);dhx.delay(function(){dhx.ze=!0;for(var a=0;a<dhx.ob.length;a++)dhx.ob[a].call();dhx.ob=[]})})})();dhx.ui={};dhx.ui.zIndex=function(){return dhx.ui.hc++};dhx.ui.hc=1;
|
||||
dhx.ready(function(){dhx.event(document.body,"click",function(a){dhx.callEvent("onClick",[a||event])})});
|
||||
(function(){var a={};dhx.Template=function(b){if(typeof b=="function")return b;if(a[b])return a[b];b=(b||"").toString();if(b.indexOf("->")!=-1)switch(b=b.split("->"),b[0]){case "html":b=dhx.html.getValue(b[1]);break;case "http":b=(new dhx.ajax).sync().get(b[1],{uid:dhx.uid()}).responseText}b=(b||"").toString();b=b.replace(/(\r\n|\n)/g,"\\n");b=b.replace(/(\")/g,'\\"');b=b.replace(/\{obj\.([^}?]+)\?([^:]*):([^}]*)\}/g,'"+(obj.$1?"$2":"$3")+"');b=b.replace(/\{common\.([^}\(]*)\}/g,"\"+(common.$1||'')+\"");
|
||||
b=b.replace(/\{common\.([^\}\(]*)\(\)\}/g,'"+(common.$1?common.$1(obj,common):"")+"');b=b.replace(/\{obj\.([^}]*)\}/g,"\"+(obj.$1||'')+\"");b=b.replace(/#([$a-z0-9_\[\]]+)#/gi,"\"+(obj.$1||'')+\"");b=b.replace(/\{obj\}/g,'"+obj+"');b=b.replace(/\{-obj/g,"{obj");b=b.replace(/\{-common/g,"{common");b='return "'+b+'";';try{Function("obj","common",b)}catch(c){}return a[b]=Function("obj","common",b)};dhx.Template.empty=function(){return""};dhx.Template.bind=function(a){return dhx.bind(dhx.Template(a),
|
||||
this)};dhx.Type=function(a,c){if(a.Ya){if(!a.Ga)a.Ga=[];a.Ga.push(c)}else{if(typeof a=="function")a=a.prototype;if(!a.types)a.types={"default":a.type},a.type.name="default";var d=c.name,e=a.type;d&&(e=a.types[d]=dhx.copy(a.type));for(var f in c)e[f]=f.indexOf("template")===0?dhx.Template(c[f]):c[f];return d}}})();
|
||||
dhx.AtomRender={xa:function(a){return this.a.template(a,this)},render:function(){if(this.isVisible(this.a.id)){if(!this.callEvent||this.callEvent("onBeforeRender",[this.data])){if(this.data)this.d.innerHTML=this.xa(this.data);this.callEvent&&this.callEvent("onAfterRender",[])}return!0}return!1},template_setter:dhx.Template};
|
||||
dhx.SingleRender=dhx.proto({xa:function(a){return this.type.templateStart(a,this.type)+this.type.template(a,this.type)+this.type.templateEnd(a,this.type)},customize:function(a){dhx.Type(this,a)}},dhx.AtomRender);
|
||||
dhx.Destruction={$init:function(){dhx.destructors.push(this)},destructor:function(){this.destructor=function(){};if(this.c)for(var a=0;a<this.c.length;a++)this.c[a].destructor();delete dhx.ui.views[this.a.id];this.af=this.B=null;this.F&&document.body.appendChild(this.F);this.F=null;if(this.g)this.g.innerHTML="",this.g.B=null;this.g=this.d=null;this.a.container&&this.b.parentNode?this.b.parentNode.parentNode.removeChild(this.b.parentNode):this.b&&this.b.parentNode&&this.b.parentNode.removeChild(this.b);
|
||||
this.data=null;this.o=this.ka={}}};dhx.destructors=[];dhx.event(window,"unload",function(){for(var a=0;a<dhx.destructors.length;a++)dhx.destructors[a].destructor();dhx.destructors=[];for(var b in dhx.o){var c=dhx.o[b];c[0].removeEventListener?c[0].removeEventListener(c[1],c[2],!1):c[0].detachEvent&&c[0].detachEvent("on"+c[1],c[2]);delete dhx.o[b]}});
|
||||
dhx.Settings={$init:function(){this.a=this.config={}},define:function(a,b){return typeof a=="object"?this.Uc(a):this.xc(a,b)},xc:function(a,b){var c=this[a+"_setter"];return this.a[a]=c?c.call(this,b,a):b},Uc:function(a){if(a)for(var b in a)this.xc(b,a[b])},Rb:function(a,b){var c={};b&&(c=dhx.extend(c,b));typeof a=="object"&&!a.tagName&&dhx.extend(c,a,!0);this.Uc(c)},Ia:function(a,b){for(var c in b)switch(typeof a[c]){case "object":a[c]=this.Ia(a[c]||{},b[c]);break;case "undefined":a[c]=b[c]}return a}};
|
||||
dhx.ajax=function(a,b,c){if(arguments.length!==0){var d=new dhx.ajax;if(c)d.master=c;d.get(a,null,b)}return!this.getXHR?new dhx.ajax:this};
|
||||
dhx.ajax.prototype={getXHR:function(){return dhx.env.isIE?new ActiveXObject("Microsoft.xmlHTTP"):new XMLHttpRequest},send:function(a,b,c){var d=this.getXHR();typeof c=="function"&&(c=[c]);if(typeof b=="object"){var e=[],f;for(f in b){var g=b[f];if(g===null||g===dhx.undefined)g="";e.push(f+"="+encodeURIComponent(g))}b=e.join("&")}b&&!this.post&&(a=a+(a.indexOf("?")!=-1?"&":"?")+b,b=null);d.open(this.post?"POST":"GET",a,!this.Te);this.post&&d.setRequestHeader("Content-type","application/x-www-form-urlencoded");
|
||||
var h=this;d.onreadystatechange=function(){if(!d.readyState||d.readyState==4){if(c&&h)for(var a=0;a<c.length;a++)c[a]&&c[a].call(h.master||h,d.responseText,d.responseXML,d);c=h=h.master=null}};d.send(b||null);return d},get:function(a,b,c){this.post=!1;return this.send(a,b,c)},post:function(a,b,c){this.post=!0;return this.send(a,b,c)},sync:function(){this.Te=!0;return this}};
|
||||
dhx.AtomDataLoader={$init:function(a){this.data={};if(a)this.a.datatype=a.datatype||"json",this.$ready.push(this.fe)},fe:function(){this.Xc=!0;this.a.url&&this.url_setter(this.a.url);this.a.data&&this.data_setter(this.a.data)},url_setter:function(a){if(!this.Xc)return a;this.load(a,this.a.datatype);return a},data_setter:function(a){if(!this.Xc)return a;this.parse(a,this.a.datatype);return!0},load:function(a,b,c){this.callEvent("onXLS",[]);typeof b=="string"?(this.data.driver=dhx.DataDriver[b],b=c):
|
||||
this.data.driver=dhx.DataDriver.json;dhx.ajax(a,[this.mb,b],this)},parse:function(a,b){this.callEvent("onXLS",[]);this.data.driver=dhx.DataDriver[b||"json"];this.mb(a,null)},mb:function(a,b){var c=this.data.driver,d=c.getRecords(c.toObject(a,b))[0];this.data=c?c.getDetails(d):a;this.callEvent("onXLE",[])},sc:function(a){if(!this.a.dataFeed||this.Gc||!a)return!0;var b=this.a.dataFeed,b=b+(b.indexOf("?")==-1?"?":"&")+"action=get&id="+encodeURIComponent(a.id||a);this.callEvent("onXLS",[]);dhx.ajax(b,
|
||||
function(a){this.Gc=!0;this.setValues(dhx.DataDriver.json.toObject(a)[0]);this.Gc=!1;this.callEvent("onXLE",[])},this);return!1}};dhx.DataDriver={};dhx.DataDriver.json={toObject:function(a){a||(a="[]");if(typeof a=="string")eval("dhx.temp="+a),a=dhx.temp;if(a.data){var b=a.data;b.pos=a.pos;b.total_count=a.total_count;a=b}return a},getRecords:function(a){return a&&!dhx.isArray(a)?[a]:a},getDetails:function(a){return a},getInfo:function(a){return{da:a.total_count||0,ia:a.pos||0}}};
|
||||
dhx.DataDriver.json_ext={toObject:function(a){a||(a="[]");if(typeof a=="string"){var b;eval("temp="+a);dhx.temp=[];for(var c=b.header,d=0;d<b.data.length;d++){for(var e={},f=0;f<c.length;f++)typeof b.data[d][f]!="undefined"&&(e[c[f]]=b.data[d][f]);dhx.temp.push(e)}return dhx.temp}return a},getRecords:function(a){return a&&!dhx.isArray(a)?[a]:a},getDetails:function(a){return a},getInfo:function(a){return{da:a.total_count||0,ia:a.pos||0}}};
|
||||
dhx.DataDriver.html={toObject:function(a){if(typeof a=="string"){var b=null;a.indexOf("<")==-1&&(b=dhx.toNode(a));if(!b)b=document.createElement("DIV"),b.innerHTML=a;return b.getElementsByTagName(this.tag)}return a},getRecords:function(a){return a.tagName?a.childNodes:a},getDetails:function(a){return dhx.DataDriver.xml.tagToObject(a)},getInfo:function(){return{da:0,ia:0}},tag:"LI"};
|
||||
dhx.DataDriver.jsarray={toObject:function(a){return typeof a=="string"?(eval("dhx.temp="+a),dhx.temp):a},getRecords:function(a){return a},getDetails:function(a){for(var b={},c=0;c<a.length;c++)b["data"+c]=a[c];return b},getInfo:function(){return{da:0,ia:0}}};
|
||||
dhx.DataDriver.csv={toObject:function(a){return a},getRecords:function(a){return a.split(this.row)},getDetails:function(a){for(var a=this.stringToArray(a),b={},c=0;c<a.length;c++)b["data"+c]=a[c];return b},getInfo:function(){return{da:0,ia:0}},stringToArray:function(a){for(var a=a.split(this.cell),b=0;b<a.length;b++)a[b]=a[b].replace(/^[ \t\n\r]*(\"|)/g,"").replace(/(\"|)[ \t\n\r]*$/g,"");return a},row:"\n",cell:","};
|
||||
dhx.DataDriver.xml={toObject:function(a,b){return b&&(b=this.checkResponse(a,b))?b:typeof a=="string"?this.fromString(a):a},getRecords:function(a){return this.xpath(a,this.records)},records:"/*/item",getDetails:function(a){return this.tagToObject(a,{})},getInfo:function(a){return{da:a.documentElement.getAttribute("total_count")||0,ia:a.documentElement.getAttribute("pos")||0}},xpath:function(a,b){if(window.XPathResult){var c=a;if(a.nodeName.indexOf("document")==-1)a=a.ownerDocument;for(var d=[],e=
|
||||
a.evaluate(b,c,null,XPathResult.ANY_TYPE,null),f=e.iterateNext();f;)d.push(f),f=e.iterateNext();return d}else{var g=!0;try{typeof a.selectNodes=="undefined"&&(g=!1)}catch(h){}if(g)return a.selectNodes(b);else{var i=b.split("/").pop();return a.getElementsByTagName(i)}}},tagToObject:function(a,b){var b=b||{},c=!1,d=a.attributes;if(d&&d.length){for(var e=0;e<d.length;e++)b[d[e].name]=d[e].value;c=!0}for(var f=a.childNodes,g={},e=0;e<f.length;e++)if(f[e].nodeType==1){var h=f[e].tagName;typeof b[h]!="undefined"?
|
||||
(dhx.isArray(b[h])||(b[h]=[b[h]]),b[h].push(this.tagToObject(f[e],{}))):b[f[e].tagName]=this.tagToObject(f[e],{});c=!0}if(!c)return this.nodeValue(a);b.value=this.nodeValue(a);return b},nodeValue:function(a){return a.firstChild?a.firstChild.data:""},fromString:function(a){if(window.DOMParser)return(new DOMParser).parseFromString(a,"text/xml");if(window.ActiveXObject){var b=new ActiveXObject("Microsoft.xmlDOM");b.loadXML(a);return b}},checkResponse:function(a,b){if(b&&b.firstChild&&b.firstChild.tagName!=
|
||||
"parsererror")return b;var c=this.fromString(a.replace(/^[\s]+/,""));if(c)return c}};
|
||||
dhx.DataLoader=dhx.proto({$init:function(a){a=a||"";name="DataStore";this.data=a.datastore||new dhx.DataStore;this.Ub=this.data.attachEvent("onStoreLoad",dhx.bind(this.Ed,this))},load:function(a,b){dhx.AtomDataLoader.load.apply(this,arguments);if(!this.data.feed)this.data.url=a,this.data.feed=function(b,d){if(this.ib)return this.ib=[b,d];else this.ib=!0;this.load(a+(a.indexOf("?")==-1?"?":"&")+"start="+b+"&count="+d,function(){var a=this.ib;this.ib=!1;typeof a=="object"?this.data.feed.apply(this,
|
||||
a):this.showItem&&this.dataCount()>b+1&&this.showItem(this.idByIndex(b+1))})}},loadNext:function(a,b){this.data.feed&&this.data.feed.call(this,b||this.dataCount(),a)},mb:function(a,b){this.data.ue(this.data.driver.toObject(a,b));this.callEvent("onXLE",[]);if(this.Ub)this.data.detachEvent(this.Ub),this.Ub=null},scheme_setter:function(a){this.data.scheme(a)},dataFeed_setter:function(a){this.data.attachEvent("onBeforeFilter",dhx.bind(function(a,c){if(this.a.dataFeed){var d={};if(a||d){if(typeof a=="function"){if(!c)return;
|
||||
a(c,d)}else d={text:c};this.clearAll();var e=this.a.dataFeed,f=[],g;for(g in d)f.push("dhx_filter["+g+"]="+encodeURIComponent(d[g]));this.load(e+(e.indexOf("?")<0?"?":"&")+f.join("&"),this.a.datatype);return!1}}},this));return a},Ed:function(){if(this.a.ready){var a=dhx.toFunctor(this.a.ready);a&&a.call&&a.apply(this,arguments)}}},dhx.AtomDataLoader).prototype;dhx.DataStore=function(){this.name="DataStore";dhx.extend(this,dhx.EventSystem);this.setDriver("xml");this.pull={};this.order=dhx.toArray()};
|
||||
dhx.DataStore.prototype={setDriver:function(a){this.driver=dhx.DataDriver[a]},ue:function(a){this.callEvent("onParse",[this.driver,a]);this.p&&this.filter();var b=this.driver.getInfo(a),c=this.driver.getRecords(a),d=(b.ia||0)*1;if(d===0&&this.order[0])d=this.order.length;for(var e=0,f=0;f<c.length;f++){var g=this.driver.getDetails(c[f]),h=this.id(g);this.pull[h]||(this.order[e+d]=h,e++);this.pull[h]=g;this.extraParser&&this.extraParser(g);this.sb&&(this.tb?this.tb(g):this.ta&&this.ta(g))}if(!this.order[b.da-
|
||||
1])this.order[b.da-1]=dhx.undefined;this.callEvent("onStoreLoad",[this.driver,a]);this.refresh()},id:function(a){return a.id||(a.id=dhx.uid())},changeId:function(a,b){this.pull[b]=this.pull[a];this.pull[b].id=b;this.order[this.order.find(a)]=b;this.p&&(this.p[this.p.find(a)]=b);this.callEvent("onIdChange",[a,b]);this.Zb&&this.Zb(a,b);delete this.pull[a]},item:function(a){return this.pull[a]},update:function(a,b){this.ta&&this.ta(b);if(this.callEvent("onBeforeUpdate",[a,b])===!1)return!1;this.pull[a]=
|
||||
b;this.refresh(a)},refresh:function(a){this.hd||(a?this.callEvent("onStoreUpdated",[a,this.pull[a],"update"]):this.callEvent("onStoreUpdated",[null,null,null]))},silent:function(a,b){this.hd=!0;a.call(b||this);this.hd=!1},getRange:function(a,b){a=a?this.indexById(a):this.startOffset||0;b?b=this.indexById(b):(b=Math.min(this.endOffset||Infinity,this.dataCount()-1),b<0&&(b=0));if(a>b)var c=b,b=a,a=c;return this.getIndexRange(a,b)},getIndexRange:function(a,b){for(var b=Math.min(b||Infinity,this.dataCount()-
|
||||
1),c=dhx.toArray(),d=a||0;d<=b;d++)c.push(this.item(this.order[d]));return c},dataCount:function(){return this.order.length},exists:function(a){return!!this.pull[a]},move:function(a,b){if(!(a<0||b<0)){var c=this.idByIndex(a),d=this.item(c);this.order.removeAt(a);this.order.insertAt(c,Math.min(this.order.length,b));this.callEvent("onStoreUpdated",[c,d,"move"])}},scheme:function(a){this.sb=a;this.tb=a.$init;this.ta=a.$update;this.ad=a.$serialize;delete a.$init;delete a.$update;delete a.$serialize},
|
||||
sync:function(a,b,c){typeof b!="function"&&(c=b,b=null);if(dhx.debug_bind)this.debug_sync_master=a;if(a.name!="DataStore")a=a.data;var d=dhx.bind(function(){this.order=dhx.toArray([].concat(a.order));this.p=null;this.pull=a.pull;b&&this.silent(b);this.Tc&&this.Tc();c?c=!1:this.refresh()},this);a.attachEvent("onStoreUpdated",d);d()},add:function(a,b){if(this.sb){var a=a||{},c;for(c in this.sb)a[c]=a[c]||this.sb[c];this.tb?this.tb(a):this.ta&&this.ta(a)}var d=this.id(a),e=this.dataCount();if(dhx.isNotDefined(b)||
|
||||
b<0)b=e;b>e&&(b=Math.min(this.order.length,b));if(this.callEvent("onBeforeAdd",[d,a,b])===!1)return!1;if(this.exists(d))return null;this.pull[d]=a;this.order.insertAt(d,b);if(this.p){var f=this.p.length;!b&&this.order.length&&(f=0);this.p.insertAt(d,f)}this.callEvent("onafterAdd",[d,b]);this.callEvent("onStoreUpdated",[d,a,"add"]);return d},remove:function(a){if(dhx.isArray(a))for(var b=0;b<a.length;b++)this.remove(a[b]);else{if(this.callEvent("onBeforeDelete",[a])===!1)return!1;if(!this.exists(a))return null;
|
||||
var c=this.item(a);this.order.remove(a);this.p&&this.p.remove(a);delete this.pull[a];this.callEvent("onafterdelete",[a]);this.callEvent("onStoreUpdated",[a,c,"delete"])}},clearAll:function(){this.pull={};this.order=dhx.toArray();this.p=null;this.callEvent("onClearAll",[]);this.refresh()},idByIndex:function(a){return this.order[a]},indexById:function(a){var b=this.order.find(a);return b},next:function(a,b){return this.order[this.indexById(a)+(b||1)]},first:function(){return this.order[0]},last:function(){return this.order[this.order.length-
|
||||
1]},previous:function(a,b){return this.order[this.indexById(a)-(b||1)]},sort:function(a,b,c){var d=a;typeof a=="function"?d={as:a,dir:b}:typeof a=="string"&&(d={by:a,dir:b,as:c});var e=[d.by,d.dir,d.as];if(this.callEvent("onbeforesort",e)){if(this.order.length){var f=dhx.sort.create(d),g=this.getRange(this.first(),this.last());g.sort(f);this.order=g.map(function(a){return this.id(a)},this)}this.refresh();this.callEvent("onaftersort",e)}},filter:function(a,b,c){if(this.callEvent("onBeforeFilter",[a,
|
||||
b])){if(this.p&&!c)this.order=this.p,delete this.p;if(this.order.length){if(a){var d=a,b=b||"";typeof a=="string"&&(a=dhx.Template(a),b=b.toString().toLowerCase(),d=function(b,c){return a(b).toLowerCase().indexOf(c)!=-1});for(var e=dhx.toArray(),f=0;f<this.order.length;f++){var g=this.order[f];d(this.item(g),b)&&e.push(g)}if(!c)this.p=this.order;this.order=e}this.refresh();this.callEvent("onAfterFilter",[])}}},each:function(a,b){for(var c=0;c<this.order.length;c++)a.call(b||this,this.item(this.order[c]))},
|
||||
provideApi:function(a,b){this.debug_bind_master=a;b&&this.mapEvent({onbeforesort:a,onaftersort:a,onbeforeadd:a,onafteradd:a,onbeforedelete:a,onafterdelete:a,onbeforeupdate:a});for(var c="sort,add,remove,exists,idByIndex,indexById,item,update,refresh,dataCount,filter,next,previous,clearAll,first,last,serialize,sync".split(","),d=0;d<c.length;d++)a[c[d]]=dhx.methodPush(this,c[d])},serialize:function(){for(var a=this.order,b=[],c=0;c<a.length;c++){var d=this.pull[a[c]];if(this.ad&&(d=this.ad(d),d===
|
||||
!1))continue;b.push(d)}return b}};
|
||||
dhx.sort={create:function(a){return dhx.sort.dir(a.dir,dhx.sort.by(a.by,a.as))},as:{"int":function(a,b){a*=1;b*=1;return a>b?1:a<b?-1:0},string_strict:function(a,b){a=a.toString();b=b.toString();return a>b?1:a<b?-1:0},string:function(a,b){a=a.toString().toLowerCase();b=b.toString().toLowerCase();return a>b?1:a<b?-1:0}},by:function(a,b){if(!a)return b;typeof b!="function"&&(b=dhx.sort.as[b||"string"]);a=dhx.Template(a);return function(c,d){return b(a(c),a(d))}},dir:function(a,b){return a=="asc"?b:
|
||||
function(a,d){return b(a,d)*-1}}};
|
||||
dhx.BaseBind={bind:function(a,b,c){typeof a=="string"&&(a=dhx.ui.get(a));a.Lb&&a.Lb();this.Lb&&this.Lb();a.getBindData||dhx.extend(a,dhx.BindSource);if(!this.zd){var d=this.render;if(this.filter){var e=this.a.id;this.data.Tc=function(){a.Va[e]=!1}}this.render=function(){if(!this.Hc)return this.Hc=!0,this.callEvent("onBindRequest"),this.Hc=!1,d.call(this)};if(this.getValue||this.getValues)this.save=function(){if(!this.validate||this.validate())a.setBindData(this.getValue?this.getValue:this.getValues(),
|
||||
this.a.id)};this.zd=!0}a.addBind(this.a.id,b,c);this.attachEvent(this.touchable?"onAfterRender":"onBindRequest",function(){a.getBindData(this.a.id)});this.isVisible(this.a.id)&&this.refresh()}};
|
||||
dhx.BindSource={$init:function(){this.Ua={};this.Va={};this.Kb={};this.Ad(this)},setBindData:function(a,b){b&&(this.Kb[b]=!0);if(this.setValue)this.setValue(a);else if(this.setValues)this.setValues(a);else{var c=this.getCursor();c&&(a=dhx.extend(this.item(c),a,!0),this.update(c,a))}this.callEvent("onBindUpdate",[a,b]);this.save&&this.save();b&&(this.Kb[b]=!1)},getBindData:function(a,b){if(!this.Va[a]){var c=dhx.ui.get(a);c.isVisible(c.a.id)&&(this.Va[a]=!0,this.Ab(c,this.Ua[a][0],this.Ua[a][1]),b&&
|
||||
c.filter&&c.refresh())}},addBind:function(a,b,c){this.Ua[a]=[b,c]},Ad:function(a){a.filter?dhx.extend(this,dhx.CollectionBind):a.setValue?dhx.extend(this,dhx.ValueBind):dhx.extend(this,dhx.RecordBind)},vb:function(){for(var a in this.Ua)this.Kb[a]||(this.Va[a]=!1,this.getBindData(a,!0))},nc:function(a,b,c){a.setValue?a.setValue(c?c[b]:c):a.filter?a.data.silent(function(){this.filter(b,c)}):!c&&a.clear?a.clear():a.sc(c)&&a.setValues(dhx.copy(c))}};
|
||||
dhx.DataValue=dhx.proto({name:"DataValue",isVisible:function(){return!0},$init:function(a){var b=(this.data=a)&&a.id?a.id:dhx.uid();this.a={id:b};dhx.ui.views[b]=this},setValue:function(a){this.data=a;this.callEvent("onChange",[a])},getValue:function(){return this.data},refresh:function(){this.callEvent("onBindRequest")}},dhx.EventSystem,dhx.BaseBind);
|
||||
dhx.DataRecord=dhx.proto({name:"DataRecord",isVisible:function(){return!0},$init:function(a){this.data=a||{};var b=a&&a.id?a.id:dhx.uid();this.a={id:b};dhx.ui.views[b]=this},getValues:function(){return this.data},setValues:function(a){this.data=a;this.callEvent("onChange",[a])},refresh:function(){this.callEvent("onBindRequest")}},dhx.EventSystem,dhx.BaseBind);
|
||||
dhx.DataCollection=dhx.proto({name:"DataCollection",isVisible:function(){return!this.data.order.length&&!this.data.p&&!this.a.dataFeed?!1:!0},$init:function(a){this.data.provideApi(this,!0);var b=a&&a.id?a.id:dhx.uid();this.a.id=b;dhx.ui.views[b]=this;this.data.attachEvent("onStoreLoad",dhx.bind(function(){this.callEvent("onBindRequest",[])},this))},refresh:function(){this.callEvent("onBindRequest",[])}},dhx.EventSystem,dhx.DataLoader,dhx.BaseBind,dhx.Settings);
|
||||
dhx.ValueBind={$init:function(){this.attachEvent("onChange",this.vb)},Ab:function(a,b,c){var d=this.getValue()||"";c&&(d=c(d));if(a.setValue)a.setValue(d);else if(a.filter)a.data.silent(function(){this.filter(b,d)});else{var e={};e[b]=d;a.sc(d)&&a.setValues(e)}}};dhx.RecordBind={$init:function(){this.attachEvent("onChange",this.vb)},Ab:function(a,b){var c=this.getValues()||null;this.nc(a,b,c)}};
|
||||
dhx.CollectionBind={$init:function(){this.X=null;this.attachEvent("onSelectChange",function(){this.setCursor(this.getSelected())});this.attachEvent("onAfterCursorChange",this.vb);this.data.attachEvent("onStoreUpdated",dhx.bind(function(a){a&&a==this.getCursor()&&this.vb()},this));this.data.attachEvent("onClearAll",dhx.bind(function(){this.X=null},this));this.data.attachEvent("onIdChange",dhx.bind(function(a,b){if(this.X==a)this.X=b},this))},setCursor:function(a){if(!(a==this.X||a!==null&&!this.item(a)))this.callEvent("onBeforeCursorChange",
|
||||
[this.X]),this.X=a,this.callEvent("onAfterCursorChange",[a])},getCursor:function(){return this.X},Ab:function(a,b){var c=this.item(this.getCursor())||null;this.nc(a,b,c)}};
|
||||
dhx.DragControl={N:dhx.toArray(["dummy"]),addDrop:function(a,b,c){a=dhx.toNode(a);a.dhx_drop=this.zc(b);if(c)a.dhx_master=!0},zc:function(a){var a=a||dhx.DragControl,b=this.N.find(a);if(b<0)b=this.N.length,this.N.push(a);return b},addDrag:function(a,b){a=dhx.toNode(a);a.dhx_drag=this.zc(b);dhx.event(a,"mousedown",this.ve,a)},ve:function(a){dhx.DragControl.O&&(dhx.DragControl.Sb(),dhx.DragControl.destroyDrag());dhx.DragControl.O=this;dhx.DragControl.jd={x:a.pageX,y:a.pageY};dhx.DragControl.$c=a;dhx.DragControl.Ea=
|
||||
dhx.event(document.body,"mousemove",dhx.DragControl.Pe);dhx.DragControl.Fa=dhx.event(document.body,"mouseup",dhx.DragControl.Sb);a.cancelBubble=!0;return!1},Sb:function(){dhx.DragControl.Ea=dhx.eventRemove(dhx.DragControl.Ea);dhx.DragControl.Fa=dhx.eventRemove(dhx.DragControl.Fa)},Pe:function(a){var b={x:a.pageX,y:a.pageY};if(!(Math.abs(b.x-dhx.DragControl.jd.x)<5&&Math.abs(b.y-dhx.DragControl.jd.y)<5)&&(dhx.DragControl.Sb(),dhx.DragControl.createDrag(dhx.DragControl.$c)))dhx.DragControl.sendSignal("start"),
|
||||
dhx.DragControl.Ea=dhx.event(document.body,"mousemove",dhx.DragControl.Oc),dhx.DragControl.Fa=dhx.event(document.body,"mouseup",dhx.DragControl.Qe),dhx.DragControl.Oc(a)},Qe:function(a){dhx.DragControl.Ea=dhx.eventRemove(dhx.DragControl.Ea);dhx.DragControl.Fa=dhx.eventRemove(dhx.DragControl.Fa);dhx.DragControl.$c=null;dhx.DragControl.C&&(dhx.DragControl.onDrop(dhx.DragControl.O,dhx.DragControl.C,this.gb,a),dhx.DragControl.onDragOut(dhx.DragControl.O,dhx.DragControl.C,null,a));dhx.DragControl.destroyDrag();
|
||||
dhx.DragControl.sendSignal("stop")},Oc:function(a){var b=dhx.html.pos(a);dhx.DragControl.F.style.top=b.y+dhx.DragControl.top+"px";dhx.DragControl.F.style.left=b.x+dhx.DragControl.left+"px";dhx.DragControl.gd?dhx.DragControl.gd=!1:dhx.DragControl.Fd(a.srcElement||a.target,a);a.cancelBubble=!0;return!1},Fd:function(a,b){for(;a&&a.tagName!="BODY";){if(a.dhx_drop){if(this.C&&(this.C!=a||a.dhx_master))this.onDragOut(this.O,this.C,a,b);if(!this.C||this.C!=a||a.dhx_master)if(this.C=null,this.gb=this.onDragIn(dhx.DragControl.O,
|
||||
a,b))this.C=a;return}a=a.parentNode}if(this.C)this.C=this.gb=this.onDragOut(this.O,this.C,null,b)},sendSignal:function(a){dhx.DragControl.active=a=="start"},getMaster:function(a){return this.N[a.dhx_drag||a.dhx_drop]},getContext:function(){return this.Za},getNode:function(){return this.F},createDrag:function(a){var b=dhx.DragControl.O;dhx.DragControl.Za={};var c=this.N[b.dhx_drag],d;if(c.onDragCreate){d=c.onDragCreate(b,a);if(!d)return!1;d.style.position="absolute";d.style.zIndex=dhx.ui.zIndex()}else{var e=
|
||||
dhx.DragControl.onDrag(b,a);if(!e)return!1;d=document.createElement("DIV");d.innerHTML=e;d.className="dhx_drag_zone";document.body.appendChild(d)}d.onmousemove=dhx.DragControl.Ne;if(!dhx.DragControl.Za.from)dhx.DragControl.Za={source:b,from:b};dhx.DragControl.F=d;return!0},Ne:function(){dhx.DragControl.gd=!0},destroyDrag:function(){var a=dhx.DragControl.O,b=this.N[a.dhx_drag];if(b&&b.onDragDestroy)b.onDragDestroy(a,dhx.DragControl.F);else dhx.html.remove(dhx.DragControl.F);dhx.DragControl.gb=dhx.DragControl.O=
|
||||
dhx.DragControl.C=dhx.DragControl.F=null},top:5,left:5,onDragIn:function(a,b,c){var d=this.N[b.dhx_drop];if(d.onDragIn&&d!=this)return d.onDragIn(a,b,c);b.className+=" dhx_drop_zone";return b},onDragOut:function(a,b,c,d){var e=this.N[b.dhx_drop];if(e.onDragOut&&e!=this)return e.onDragOut(a,b,c,d);b.className=b.className.replace("dhx_drop_zone","");return null},onDrop:function(a,b,c,d){var e=this.N[b.dhx_drop];dhx.DragControl.Za.from=dhx.DragControl.getMaster(a);if(e.onDrop&&e!=this)return e.onDrop(a,
|
||||
b,c,d);b.appendChild(a)},onDrag:function(a,b){var c=this.N[a.dhx_drag];return c.onDrag&&c!=this?c.onDrag(a,b):"<div style='"+a.style.cssText+"'>"+a.innerHTML+"</div>"}};
|
||||
dhx.DataMove={$init:function(){},copy:function(a,b,c,d){var e=this.item(a);if(e)return c&&(e=c.externalData(e)),c=c||this,c.add(c.externalData(e,d),b)},move:function(a,b,c,d){if(dhx.isArray(a))for(var e=0;e<a.length;e++){var f=(c||this).indexById(this.move(a[e],b,c,d?d[e]:null));a[e+1]&&(b=f+(this.indexById(a[e+1])<f?0:1))}else{var g=a;if(!(b<0)){var h=this.item(a);if(h){if(!c||c==this)this.data.move(this.indexById(a),b);else{if(!d||c.item(d))d=dhx.uid();g=c.add(c.externalData(h,d),b);this.remove(a)}return g}}}},
|
||||
moveUp:function(a,b){return this.move(a,this.indexById(a)-(b||1))},moveDown:function(a,b){return this.moveUp(a,(b||1)*-1)},moveTop:function(a){return this.move(a,0)},moveBottom:function(a){return this.move(a,this.data.dataCount()-1)},externalData:function(a,b){var c=dhx.extend({},a);c.id=b||dhx.uid();c.$selected=c.$template=null;return c}};
|
||||
dhx.Movable={move_setter:function(a){if(a)this.kb=dhx.copy(this.kb),this.kb.master=this,dhx.DragControl.addDrag(this.eb,this.kb)},kb:{onDragCreate:function(a,b){var c=dhx.html.offset(a),d=dhx.html.pos(b);dhx.DragControl.top=c.y-d.y;dhx.DragControl.left=c.x-d.x;return dhx.toNode(this.master.b)},onDragDestroy:function(){dhx.DragControl.top=dhx.DragControl.left=5}}};
|
||||
dhx.Scrollable={$init:function(a){if(a&&!a.scroll&&this.se)return this.d=this.d||this.g;(this.d||this.g).appendChild(dhx.html.create("DIV",{"class":"dhx_scroll_cont"},""));this.d=(this.d||this.g).firstChild},scrollSize:dhx.Touch?0:18,scroll_setter:function(a){if(!a)return!1;dhx.Touch?(a=a=="x"?"x":a=="xy"?"xy":"y",this.d.setAttribute("touch_scroll",a),this.attachEvent&&this.attachEvent("onAfterRender",dhx.bind(this.Ae,this)),this.a.touch_scroll=!0):this.d.parentNode.style.overflowY=a?"scroll":"";
|
||||
return a},scrollState:function(){if(dhx.Touch){var a=dhx.Touch.Hb(this.d);return{x:-a.e,y:-a.f}}else return{x:this.d.parentNode.scrollLeft,y:this.d.parentNode.scrollTop}},scrollTo:function(a,b){dhx.Touch?(b=Math.max(0,Math.min(b,this.d.offsetHeight-this.m)),a=Math.max(0,Math.min(a,this.d.offsetWidth-this.j)),dhx.Touch.wa(this.d,-a,-b,this.a.scrollSpeed||"100ms")):(this.d.parentNode.scrollLeft=a,this.d.parentNode.scrollTop=b)},Ae:function(){if(this.a.scroll.indexOf("x")!=-1&&!this.Yd)this.d.style.width=
|
||||
this.j+"px",this.d.style.width=this.d.scrollWidth+"px";dhx.Touch&&this.a.touch_scroll&&(dhx.Touch.Ca(),dhx.Touch.ua(),dhx.Touch.wa(this.d,0,0,0))}};
|
||||
dhx.ActiveContent={$init:function(a){if(a.activeContent){this.$ready.push(this.be);this.Qa={};this.Ra={};this.za={};this.yb={};for(var b in a.activeContent)if(this[b]=this.yd(b),a.activeContent[b].earlyInit){var c=dhx.D;dhx.D=null;this[b].call(this,{},this,a.activeContent);dhx.D=c}}},be:function(){if(this.filter){for(var a in this.a.activeContent)this.type[a]=this[a],this[a]=this.ge(a);this.type.masterUI=this}},ge:function(a){return function(b){for(var c=this.yb[a],d=c.a.id,e=this.pa(b).getElementsByTagName("DIV"),
|
||||
f=0;f<e.length;f++)if(e[f].getAttribute("view_id")==d){c.b=c.d=e[f];break}return c}},Vd:function(a,b,c){return function(d){if(d)for(var e=d.target||d.srcElement;e;){if(e.getAttribute&&e.getAttribute("view_id")){a.d=a.b=e;if(c.locate){var f=c.locate(e.parentNode),g=c.za[b][f];a.a.value=g}return e}e=e.parentNode}return a.b}},Ke:function(a,b){return function(c){var d=b.data;if(b.filter){var e=b.locate(this.b.parentNode),d=b.item(e);b.Ra[a][e]=this.b.outerHTML||(new XMLSerializer).serializeToString(this.b);
|
||||
b.za[a][e]=c}d[a]=c}},yd:function(a){return function(b,c,d){var e=c.Qa?c:c.masterUI;if(!e.Qa[a]){var f=document.createElement("DIV"),d=d||e.a.activeContent,g=dhx.ui(d[a],f);g.getNode=e.Vd(g,a,e);g.attachEvent("onChange",e.Ke(a,e));e.yb[a]=g;e.Qa[a]=f.innerHTML;e.Ra[a]={};e.za[a]={}}e.filter&&b[a]!=e.za[a]&&!dhx.isNotDefined(b[a])&&(g=e.yb[a],g.blockEvent(),g.setValue(b[a]),g.unblockEvent(),e.za[a][b.id]=b[a],e.Ra[a][b.id]=g.b.outerHTML||(new XMLSerializer).serializeToString(g.b));return e.Ra[a][b.id]||
|
||||
e.Qa[a]}}};dhx.IdSpace={$init:function(){var a=dhx.ja;this.elements={};dhx.ja=this;this.od={};this.getTopParent=dhx.bind(function(){return this},this);this.$ready.push(function(){dhx.ja=a;for(var b in this.elements)this.elements[b].mapEvent&&!this.elements[b].touchable&&this.elements[b].mapEvent({onbeforetabclick:this,onaftertabclick:this,onitemclick:this}),this.elements[b].getTopParent=this.getTopParent})},$$:function(a){return this.elements[a]},innerId:function(a){return this.od[a]}};
|
||||
(function(){var a=[],b=dhx.ui=function(c,d,e){dhx.qd=!0;var f=c,f=dhx.toNode(c.container||d||document.body),g=c.a||f.c&&!e?c:b.Oa(c);f.appendChild?(f.appendChild(g.b),!g.setPosition&&f==document.body&&a.push(g),c.skipResize||g.resize()):f.ac&&(g.getParent&&g.getParent()&&g.getParent().Zc(g),f.ac(g,e));dhx.qd=!1;return g};dhx.ui.rd=function(a){return a+(this.Pc[a]=(this.Pc[a]||0)+1)};dhx.ui.Pc={};dhx.ui.resize=function(){if(!dhx.ui.yc)for(var b=0;b<a.length;b++)a[b].resize()};dhx.event(window,"resize",
|
||||
dhx.ui.resize);b.Eb={};b.delay=function(a){dhx.ui.Eb[a.id]=a};dhx.ui.zIndex=function(){return dhx.ui.hc++};dhx.ui.hc=1;b.Oa=function(a){if(a.view){var d=a.view;delete a.view;return new b[d](a)}else return a.rows||a.cols?new b.layout(a):a.cells?new b.multiview(a):new b.template(a)};b.views={};b.get=function(a){if(!a)return null;if(b.views[a])return b.views[a];if(b.Eb[a])return dhx.ui(b.Eb[a]);var d=a;if(typeof a=="object"){if(a.a)return a;d=a.target||a.srcElement||a}return b.views[dhx.html.locate({target:dhx.toNode(d)},
|
||||
"view_id")]};if(dhx.isNotDefined(window.$$))$$=b.get;dhx.protoUI({name:"baseview",$init:function(a){if(!a.id)a.id=dhx.ui.rd(this.name);this.D=dhx.D;dhx.D=null;this.$view=this.g=this.b=dhx.html.create("DIV",{"class":"dhx_view"})},defaults:{width:-1,height:-1,gravity:1},getNode:function(){return this.b},getParent:function(){return this.D||null},isVisible:function(a){if(this.a.hidden&&a){if(!this.la)this.la=[],this.Jb={};this.Jb[a]||(this.Jb[a]=!0,this.la.push(a));return!1}var b=this.getParent();return b?
|
||||
b.isVisible(a,this.a.id):!0},container_setter:function(){return!0},css_setter:function(a){this.b.className+=" "+a;return a},id_setter:function(a){if(dhx.ja&&dhx.ja!=this){var b=a;dhx.ja.elements[a]=this;a=dhx.ui.rd(this.name);dhx.ja.od[a]=b}dhx.ui.views[a]=this;this.b.setAttribute("view_id",a);return a},$setSize:function(a,b){if(this.$&&this.$[0]==a&&this.$[1]==b)return!1;this.$=[a,b];this.j=a;this.j=a-(this.a.scroll?dhx.Scrollable.scrollSize:0);this.m=b;this.$width=this.j;this.$height=this.m;this.b.style.width=
|
||||
a+"px";this.b.style.height=b+"px";return!0},$getSize:function(){var a=this.a.width,b=this.a.height,e,f;e=f=this.a.gravity;a==-1?a=0:(e=0,a+=this.a.scroll?dhx.Scrollable.scrollSize:0);b==-1?b=0:f=0;return[e,a,f,b]},show:function(a){if(this.getParent()){var b=this.getParent();!a&&this.a.animate&&b.a.animate&&(a=dhx.extend(b.a.animate?dhx.extend({},b.a.animate):{},this.a.animate,!0));var e=arguments.length<2;if(e?b.Ma:b.Ha)(e?b.Ma:b.Ha).call(b,this,a)}},hidden_setter:function(a){a&&this.hide();return this.a.hidden},
|
||||
hide:function(){this.show(null,!0)},resize:function(){var a=this.b;if(!this.D)a=a.parentNode;if(!this.b.parentNode)return!1;var b=this.b.parentNode.offsetWidth,e=this.b.parentNode.offsetHeight,f=this.$getSize(),b=f[0]?Math.max(b,f[1]):Math.max(f[1],b),e=f[2]?Math.max(e,f[3]):Math.max(f[3],e);this.$setSize(b,e)}},dhx.Settings,dhx.Destruction,dhx.BaseBind);dhx.protoUI({name:"view",$init:function(){this.g.style.border="1px solid #AEAEAE"},$getSize:function(){var a=this.a.k,b=dhx.ui.baseview.prototype.$getSize.call(this);
|
||||
if(!a)return b;var e=(a.left?0:1)+(a.right?0:1),f=(a.top?0:1)+(a.bottom?0:1);b[1]&&e&&(b[1]+=e);b[3]&&f&&(b[3]+=f);return b},$setSize:function(a,b){var e=this.a.k;e?(a-=(e.left?0:1)+(e.right?0:1),b-=(e.top?0:1)+(e.bottom?0:1)):this.g.style.border="0px solid #AEAEAE";return dhx.ui.baseview.prototype.$setSize.call(this,a,b)}},dhx.ui.baseview)})();dhx.ui.view.call(dhx);
|
||||
dhx.protoUI({name:"baselayout",$init:function(){this.$ready.push(this.T);this.d=this.g},rows_setter:function(a){this.r=1;this.wc="";this.Q=a},cols_setter:function(a){this.r=0;this.wc="left";this.Q=a},Zc:function(a){dhx.PowerArray.removeAt.call(this.c,dhx.PowerArray.find.call(this.c,a));this.resizeChildren(!0)},ac:function(a,b){if(dhx.isNotDefined(b)){for(var c=0;c<this.c.length;c++)this.c[c].destructor();this.Q=a;this.T()}else{if(typeof b=="number"){if(b<0||b>this.c.length)b=this.c.length;var d=(this.c[b]||
|
||||
{}).b;dhx.PowerArray.insertAt.call(this.c,a,b);dhx.html.insertBefore(a.b,d,this.d)}else{var e=dhx.ui.get(b),b=dhx.PowerArray.find.call(this.c,e);e.b.parentNode.insertBefore(a.b,e.b);e.destructor();this.c[b]=a}a.b.style.cssFloat=a.b.style.styleFloat=this.wc;this.c[b].D=this}this.resizeChildren()},reconstruct:function(){for(var a=0;a<this.c.length;a++)dhx.html.remove(this.c[a].b);this.T();this.$setSize(this.$[0],this.$[1])},Ha:function(a,b,c){if(!a.a.hidden)a.a.hidden=!0,dhx.html.remove(a.b),this.fb++,
|
||||
!c&&!dhx.qd&&this.resizeChildren(!0)},resizeChildren:function(){if(this.hb){var a=this.$getSize(),b=this.hb[0],c=this.hb[1];this.va(b,c)}},index:function(a){if(a.a)a=a.a.id;for(var b=0;b<this.c.length;b++)if(this.c[b].a.id==a)return b;return-1},Ma:function(a,b,c){if(a.a.hidden)a.a.hidden=!1,dhx.html.insertBefore(a.b,(this.c[this.index(a)+1]||{}).b,this.d||this.b),this.fb--,c||this.resizeChildren(!0)},showBatch:function(a){if(this.a.visibleBatch!=a){this.a.visibleBatch=a;for(var b=[],c=0;c<this.c.length;c++)this.c[c].a.batch||
|
||||
b.push(this.c[c]),this.c[c].a.batch==a?b.push(this.c[c]):this.Ha(this.c[c],null,!0);for(c=0;c<b.length;c++)this.Ma(b[c],null,!0);this.resizeChildren()}},T:function(a){a=this.Q||a;this.Q=null;this.c=[];this.b.style.verticalAlign="top";for(var b=0;b<a.length;b++){dhx.D=this;this.c[b]=dhx.ui.Oa(a[b],this);if(!this.r)this.c[b].b.style.cssFloat=this.c[b].b.style.styleFloat="left";if(this.a.visibleBatch&&this.a.visibleBatch!=this.c[b].a.batch&&this.c[b].a.batch)this.c[b].a.hidden=!0;this.c[b].a.hidden||
|
||||
(this.d||this.g).appendChild(this.c[b].b)}},$getSize:function(){var a=0,b=0,c=0,d=0;this.U=[];for(var e=0;e<this.c.length;e++)if(!this.c[e].a.hidden){var f=this.U[e]=this.c[e].$getSize();this.r?(a=Math.max(a,f[1]),c=Math.max(c,f[0]),b+=f[3],d+=f[2]):(b=Math.max(b,f[3]),d=Math.max(d,f[2]),a+=f[1],c+=f[0])}this.jb=[c,a,d,b];if(this.a.height>-1)b=this.a.height,d=0;if(this.a.width>-1)a=this.a.width,c=0;this.r?(a&&(c=0),d&&(b=0)):(b&&(d=0),c&&(a=0));return[c,a,d,b]},$setSize:function(a,b){this.hb=[a,b];
|
||||
dhx.ui.baseview.prototype.$setSize.call(this,a,b);this.va(a,b)},va:function(a,b){for(var c=a-this.jb[1],d=b-this.jb[3],e=this.jb[0],f=this.jb[2],g=this.c.length-1,h=0;h<this.c.length;h++)if(!this.c[h].a.hidden){if(this.r){var i=a,j;this.U[h][2]?(j=Math.round(this.U[h][2]*d/f),d-=j,f-=this.U[h][2]):(j=this.U[h][3],h==g&&d>0&&(j+=d))}else j=b,this.U[h][0]?(i=Math.round(this.U[h][0]*c/e),c-=i,e-=this.U[h][0]):(i=this.U[h][1],h==g&&c>0&&(i+=c));this.c[h].$setSize(i,j)}},ef:function(a,b){var c=this.index(a);
|
||||
return c==-1?null:this.c[c+b]},first:function(){return this.c[0]}},dhx.ui.baseview);
|
||||
dhx.protoUI({name:"layout",$init:function(){this.fb=0},T:function(){this.b.className+=" dhx_layout_"+(this.a.type||"");if(this.a.margin)this.S=this.a.margin;if(this.a.padding)this.u=this.a.padding;var a=this.Q;if(!this.a.k)this.a.k={top:!0,left:!0,right:!0,bottom:!0};this.mc(a);dhx.ui.baselayout.prototype.T.call(this,a);this.kc(a)},$getSize:function(){var a=dhx.ui.baselayout.prototype.$getSize.call(this),b=this.S*(this.c.length-this.fb-1);this.r?a[3]&&(a[3]+=b):a[1]&&(a[1]+=b);if(this.u&&(a[1]&&(a[1]+=
|
||||
this.u*2),a[3]&&(a[3]+=this.u*2),this.S>-1)){var c=this.a.k;if(c){var d=(c.left?0:1)+(c.right?0:1),e=(c.top?0:1)+(c.bottom?0:1);a[1]&&d&&(a[1]+=d);a[3]&&e&&(a[3]+=e)}}return a},$setSize:function(a,b){this.hb=[a,b];this.u&&this.S>0?dhx.ui.view.prototype.$setSize.call(this,a,b):dhx.ui.baseview.prototype.$setSize.call(this,a,b);this.va(this.j,this.m)},va:function(a,b){var c=this.S*(this.c.length-this.fb-1);this.r?(b-=c+this.u*2,a-=this.u*2):(a-=c+this.u*2,b-=this.u*2);return dhx.ui.baselayout.prototype.va.call(this,
|
||||
a,b)},resizeChildren:function(a){if(a&&this.type!="clean"){for(var b=[],c=0;c<this.c.length;c++){var d=this.c[c];b[c]=d.a;d.b.style.borderTopWidth=d.b.style.borderBottomWidth=d.b.style.borderLeftWidth=d.b.style.borderRightWidth="1px"}this.mc(b);this.kc(this.c)}dhx.ui.baselayout.prototype.resizeChildren.call(this)},mc:function(a){if(this.u&&this.S)for(var b=0;b<a.length;b++)a[b].k={top:!1,left:!1,right:!1,bottom:!1};else{for(b=0;b<a.length;b++)a[b].k=dhx.copy(this.a.k);var c=!1;this.a.type=="clean"&&
|
||||
(c=!0);if(this.r){for(b=1;b<a.length-1;b++)a[b].k.top=a[b].k.bottom=c;if(a.length>1){if(this.a.type!="head")a[0].k.bottom=c;a[a.length-1].k.top=c}}else{for(b=1;b<a.length-1;b++)a[b].k.left=a[b].k.right=c;if(a.length>1){if(this.a.type!="head")a[0].k.right=c;a[a.length-1].k.left=c}}}},kc:function(a){for(var b=1,c=0;c<a.length;c++){var d=this.c[c];if(d.a.hidden&&this.c[c+1])this.c[c+1].a.k=d.a.k,c<b&&b++;var e=d.a.k;if(e.top)d.b.style.borderTopWidth="0px";if(e.left)d.b.style.borderLeftWidth="0px";if(e.right)d.b.style.borderRightWidth=
|
||||
"0px";if(e.bottom)d.b.style.borderBottomWidth="0px"}if(this.u){for(var f=this.r?"marginLeft":"marginTop",g=this.r?"marginTop":"marginLeft",c=0;c<a.length;c++)this.c[c].b.style[f]=this.u+"px";this.c[0].b.style[g]=this.u+"px"}for(var f=this.r?"marginTop":"marginLeft",h=0;h<b;h++)this.c[h].b.style[f]="0px";for(;h<a.length;h++)this.c[h].b.style[f]=this.S+"px"},type_setter:function(a){this.S=this.je[a];if((this.u=this.te[a])&&this.S>0)this.g.style.border="1px solid #AEAEAE";return a},je:{space:10,wide:4,
|
||||
clean:0,head:4,line:-1},te:{space:10,wide:0,clean:0,head:0,line:0},S:-1,u:0},dhx.ui.baselayout);dhx.ui.layout.call(dhx);
|
||||
dhx.protoUI({name:"template",$init:function(){this.attachEvent("onXLE",this.render)},setValues:function(a){this.data=a;this.render()},defaults:{template:dhx.Template.empty,loading:!0},Wc:function(){this.Pb||this.render()},src_setter:function(a){this.Pb=!0;this.callEvent("onXLS",[]);dhx.ajax(a,dhx.bind(function(a){this.a.template=dhx.Template(a);this.Pb=!1;this.Wc();this.callEvent("onXLE",[])},this));return a},content_setter:function(a){if(a)this.Pb=!0,this.d.appendChild(dhx.toNode(a))},refresh:function(){this.render()},
|
||||
waitMessage_setter:function(a){dhx.extend(this,dhx.ui.overlay);return a},$setSize:function(a,b){dhx.ui.view.prototype.$setSize.call(this,a,b)&&this.Wc()},se:!0},dhx.Scrollable,dhx.AtomDataLoader,dhx.AtomRender,dhx.EventSystem,dhx.ui.view);
|
||||
dhx.protoUI({name:"iframe",defaults:{loading:!0},$init:function(){this.d=this.g;this.g.innerHTML="<iframe style='width:100%; height:100%' frameborder='0' src='about:blank'></iframe>"},load:function(a){this.src_setter(a)},src_setter:function(a){this.g.childNodes[0].src=a;this.callEvent("onXLS",[]);dhx.delay(this.Je,this);return a},Je:function(){try{dhx.event(this.getWindow(),"load",dhx.bind(function(){this.callEvent("onXLS",[])},this))}catch(a){this.callEvent("onXLE",[])}},getWindow:function(){return this.g.childNodes[0].contentWindow},
|
||||
waitMessage_setter:function(a){dhx.extend(this,dhx.ui.overlay);return a}},dhx.ui.view,dhx.EventSystem);
|
||||
dhx.ui.overlay={$init:function(){if(dhx.isNotDefined(this.ba)&&this.attachEvent)this.attachEvent("onXLS",this.showOverlay),this.attachEvent("onXLE",this.hideOverlay),this.ba=null},showOverlay:function(){if(!this.ba)this.ba=dhx.html.create("DIV",{"class":"dhx_loading_overlay"},""),dhx.html.insertBefore(this.ba,this.b.firstChild,this.b)},hideOverlay:function(){if(this.ba)dhx.html.remove(this.ba),this.ba=null}};
|
||||
dhx.protoUI({name:"scrollview",defaults:{scroll:"x",scrollSpeed:"0ms"},$init:function(){this.b.className+=" dhx_scrollview"},content_setter:function(a){this.ha=dhx.ui.Oa(a);this.ha.D=this;this.d.appendChild(this.ha.b)},body_setter:function(a){return this.content_setter(a)},$getSize:function(){this.ga=this.ha.$getSize();if(this.a.scroll=="x"&&this.ga[3]>0)this.a.height=this.ga[3];else if(this.a.scroll=="y"&&this.ga[1]>0)this.a.width=this.ga[1];return dhx.ui.view.prototype.$getSize.call(this)},$setSize:function(a,
|
||||
b){if(dhx.ui.view.prototype.$setSize.call(this,a,b))this.ha.$setSize(Math.max(this.ga[1],this.j),Math.max(this.ga[3],this.m)),this.d.style.width=this.ha.j+"px",this.d.style.height=this.ha.m+"px"}},dhx.Scrollable,dhx.ui.view);dhx.CanvasMgr=function(a){var b=dhx.CanvasMgr.prototype.qc;!b[a]&&document.getCSSCanvasContext&&(b[a]=!0,dhx.CanvasMgr.prototype[a](b))};
|
||||
dhx.CanvasMgr.prototype={buttonGrd:["#fefefe","#e0e0e0","#e5e5e5","#e0e0e0",32],qc:[],Pa:function(a,b,c,d,e){var f=document.getCSSCanvasContext("2d",d,18,c),g=f.createLinearGradient(0,0,0,c);g.addColorStop(0,a);g.addColorStop(1,b);f.fillStyle=g;f.strokeStyle="#93B0BA";f.lineWidth=2;e?(f.moveTo(0,0.5),f.lineTo(17.5,c/2+0.5),f.lineTo(0,c-0.5),f.lineTo(0,0.5)):(f.moveTo(18,0.5),f.lineTo(0.5,c/2+0.5),f.lineTo(18,c-0.5),f.lineTo(18,0.5));f.stroke();f.fill()},dhxArrowLeftT:function(){this.Pa(this.buttonGrd[2],
|
||||
this.buttonGrd[3],this.buttonGrd[4],"dhxArrowLeftT")},dhxArrowRightT:function(){this.Pa(this.buttonGrd[2],this.buttonGrd[3],this.buttonGrd[4],"dhxArrowRightT",!0)},dhxArrowLeft:function(){this.Pa(this.buttonGrd[0],this.buttonGrd[1],this.buttonGrd[4],"dhxArrowLeft");dhx.CanvasMgr("dhxArrowLeftT")},dhxArrowRight:function(){this.Pa(this.buttonGrd[0],this.buttonGrd[1],this.buttonGrd[4],"dhxArrowRight",!0);dhx.CanvasMgr("dhxArrowRightT")}};
|
||||
dhx.attachEvent("onClick",function(a){var b=dhx.ui.get(a);if(b&&b.touchable){b.getNode(a);var c=a.target||a.srcElement,d="",e=null,f=!1;if(!(c.className&&c.className.indexOf("dhx_view")===0)){for(;c&&c.parentNode;){if(c.getAttribute){if(c.getAttribute("view_id"))break;if(d=c.className)if(d=d.split(" "),d=d[0]||d[1],b.on_click[d]){var g=b.on_click[d].call(b,a,b.a.id,c);if(g===!1)return}}c=c.parentNode}if(b.a.click){var h=dhx.toFunctor(b.a.click);h&&h.call&&h.call(b,b.a.id,a)}if(b.a.multiview){var i=
|
||||
dhx.ui.get(b.a.multiview);i&&i.show&&i.show()}if(b.a.popup){var j=dhx.ui.get(b.a.popup);j.a.master=b.a.id;j.show(b.getInput()||b.getNode(),j.h.a.align||"bottom",!0)}b.callEvent("onItemClick",[b.a.id,a])}}});
|
||||
dhx.protoUI({name:"button",touchable:!0,defaults:{template:"<div class='dhx_el_button'><input type='button' style='width:100%;' value='#label#'></div>",height:42,label:"label",s:10},$init:function(a){this.data=this.a;this.d=this.b;dhx.sa&&(dhx.sa.elements[a.name||a.id]=this,this.mapEvent({onbeforetabclick:dhx.sa,onaftertabclick:dhx.sa,onitemclick:dhx.sa}));a.type=="prev"&&dhx.CanvasMgr("dhxArrowLeft");a.type=="next"&&dhx.CanvasMgr("dhxArrowRight")},type_setter:function(a){this.a.template=dhx.Template(this.pd[a][0]);
|
||||
var b=this.pd[a][1];if(b)this.a.s=b},pd:{round:["<div class='dhx_el_roundbutton'><input type='button' style='width:100%;' value='#label#'></div>"],"default":["<div class='dhx_el_defaultbutton'><input type='button' style='width:100%;' value='#label#'></div>"],form:[function(a){return"<div class='dhx_el_formbutton'><div style='width:100%;text-align:"+a.align+"'><input type='button' class='dhx_inp_form_button' style='text-align: "+a.inputAlign+"; width: "+(a.inputWidth?a.inputWidth+"px":"100%")+";' value='"+
|
||||
(a.label||a.value)+"' /></div></div>"}],prev:["<div class='dhx_el_prevbutton'><div class='dhx_el_prevbutton_arrow'></div><div class='dhx_el_prevbutton_input_cont'><input type='button' value='#label#' /></div></div>",28],next:["<div class='dhx_el_nextbutton'><div class='dhx_el_nextbutton_input_cont'><input type='button' value='#label#' /></div><div class='dhx_el_nextbutton_arrow'></div></div>",28],big:["<div class='dhx_el_bigbutton'><input type='button' value='#label#'></div>",28],biground:["<div class='dhx_el_bigroundbutton'><input type='button' value='#label#'></div>",
|
||||
28]},$setSize:function(a,b){dhx.ui.view.prototype.$setSize.call(this,a,b)&&this.render()},K:function(a){this.a.label=a;this.getInput().value=a},getValue:function(){return this.d.childNodes.length>0?this.ab():this.a.value},setValue:function(a){var b=this.a.value;this.a.value=a;if(this.d.childNodes.length>0)this.Md=a,this.K(a),this.callEvent("onChange",[a,b])},focus:function(){this.getInput().focus()},ab:function(){return this.a.label||""},getInput:function(){return this.d.getElementsByTagName("input")[0]},
|
||||
J:function(){return this.getInput()},Z:function(){this.a.inputWidth?this.J().style.width=this.a.inputWidth-this.a.s+"px":this.J().style.width=this.j-this.a.s+"px"},render:function(){if(dhx.AtomRender.render.call(this)){this.Z();if(this.a.align)switch(this.a.align){case "right":this.d.firstChild.style.cssFloat=this.d.firstChild.style.styleFloat="right";break;case "center":this.d.firstChild.style.display="inline-block";this.d.firstChild.parentNode.style.textAlign="center";break;case "middle":this.d.firstChild.style.marginTop=
|
||||
Math.round((this.m-40)/2)+"px";break;case "bottom":this.d.firstChild.style.marginTop=this.m-40+"px";break;case "left":this.d.firstChild.parentNode.style.textAlign="left"}this.Aa&&this.Aa(this.data);this.Md!=this.a.value&&this.setValue(this.a.value)}},refresh:function(){this.render()},on_click:{Ib:function(a,b){var c=dhx.html.locate(a,"button_id");if(c&&this.callEvent("onBeforeTabClick",[b,c])){this.a.selected=c;this.refresh();if(this.a.multiview){var d=dhx.ui.get(c);d&&d.show&&d.show()}this.callEvent("onAfterTabClick",
|
||||
[b,c])}},dhx_el_segmented:function(a,b){this.on_click.Ib.call(this,a,b)},dhx_el_tabbar:function(a,b){this.on_click.Ib.call(this,a,b)},dhx_inp_counter_next:function(){this.next(this.a.step,this.a.min,this.a.max)},dhx_inp_counter_prev:function(){this.prev(this.a.step,this.a.min,this.a.max)},dhx_inp_toggle_left_off:function(){var a=this.a.options;this.setValue(a[0].value)},dhx_inp_toggle_right_off:function(){var a=this.a.options;this.setValue(a[1].value)},dhx_inp_combo:function(a,b,c){c.focus()},dhx_inp_checkbox_border:function(){this.toggle()},
|
||||
dhx_inp_checkbox_label:function(){this.toggle()},dhx_inp_radio_border:function(a){var b=dhx.html.locate(a,"radio_id");this.setValue(b)},dhx_inp_radio_label:function(a,b,c){c=c.parentNode.getElementsByTagName("input")[0];return this.on_click.dhx_inp_radio_border.call(this,c,b,c)}},Ba:function(a){for(var b=0;b<a.length;b++)if(typeof a[b]=="string")a[b]={value:a[b],label:a[b]};else if(a[b].value){if(!a[b].label)a[b].label=a[b].value}else a[b].value=a[b].label}},dhx.ui.view,dhx.AtomRender,dhx.Settings,
|
||||
dhx.EventSystem);dhx.protoUI({name:"imagebutton",defaults:{template:"<div class='dhx_el_imagebutton'><span><img src='#src#'/> #label#</span></div>",label:""},Z:function(){}},dhx.ui.button);dhx.protoUI({name:"label",defaults:{template:"<div class='dhx_el_label'>#label#</div>"},focus:function(){return!1},J:function(){return this.d.firstChild},K:function(a){this.a.label=a;this.d.firstChild.innerHTML=a}},dhx.ui.button);
|
||||
dhx.protoUI({name:"icon",defaults:{template:"<div class='dhx_el_icon'><div class='dhx_el_icon_#icon#'></div></div>",width:42},Z:function(){}},dhx.ui.button);
|
||||
dhx.protoUI({name:"segmented",defaults:{template:function(a,b){var c=a.options,d="",e;b.Ba(c);if(!a.selected)a.selected=c[0].value;for(var f=0;f<c.length;f++)e=c[f].width||a.inputWidth?"width: "+((c[f].width||Math.round(a.inputWidth/c.length))-b.a.s)+"px;":"",d+="<div style='"+e+"' class='"+(a.selected==c[f].value?"selected ":"")+"segment_"+(f==c.length-1?"N":f>0?1:0)+"' button_id='"+c[f].value+"'>"+c[f].label+"</div>";return"<div class='dhx_el_segmented'>"+d+"</div>"},s:28,nb:0},K:function(a){if(this.d&&
|
||||
this.d.firstChild)for(var b=this.d.firstChild.childNodes,c=0;c<b.length;c++)if(dhx.html.locate(b[c],"button_id")==a)return this.on_click.Ib.call(this,b[c],this.a.options[c]),!0},getValue:function(){return this.a.selected},Z:function(){}},dhx.ui.button);
|
||||
dhx.protoUI({name:"tabbar",defaults:{height:49,template:function(a,b){var c=a.options;b.Ba(c);for(var d="",e,f=0;f<c.length;f++){var g="",h=c[f].src;c[f].value==a.selected&&(g="selected",h=c[f].srcSelected||c[f].src);c[f].css&&(g+=" "+c[f].css);e=a.optionWidth||c[f].width||a.inputWidth?"width: "+(c[f].width||Math.ceil(a.inputWidth/c.length)-b.a.s)+"px;":"";d+="<div class='"+g+"' button_id='"+c[f].value+"' style='"+e+"'>";d+=h?"<img src='"+h+"'/><span>"+c[f].label+"</span>":"<div style='height:26px'></div><span>"+
|
||||
c[f].label+"</span>";d+="</div>"}return"<div class='dhx_el_tabbar'>"+d+"</div>"},s:4}},dhx.ui.segmented);
|
||||
dhx.protoUI({name:"text",wd:!0,$b:function(a,b,c){c.labelPosition=="left"?a+=b:a=b+a;return"<div class='dhx_el_"+this.name+"'>"+a+"</div>"},pb:function(a,b,c,d){var e=a.inputAlign||"left",f=a.labelAlign||"left",g=dhx.uid(),h="<div class='dhx_inp_text_border'>";h+="<div class='dhx_inp_text_label' style='width: "+this.a.labelWidth+"px; text-align: "+f+";'><label onclick='' for='"+g+"' class='dhx_inp_label_for_text'>"+(a.label||"")+"</label></div>";var i=this.a.inputWidth-this.a.labelWidth-18;i<0&&(i=
|
||||
0);h+=d?"<div class='dhx_inp_"+b+"' onclick='' style='width: "+i+"px; text-align: "+e+";' >"+(a.text||a.value||"")+"</div>":"<input id='"+g+"' type='"+(a.type||this.name)+"' value='"+(a.text||a.value||"")+"' "+(c||a.readonly?"readonly='true' ":"")+(a.maxlength?"maxlength='"+a.maxlength+"' ":"")+(a.placeholder?"placeholder='"+a.placeholder+"' ":"")+" class='dhx_inp_"+b+"' style='width: "+i+"px; text-align: "+e+";' />";h+="</div>";return"<div class='dhx_el_"+this.name+"'>"+h+"</div>"},qb:function(a,
|
||||
b){if(!a.label)return"";var c=a.labelAlign||"left";return"<div class='dhx_inp_"+b+"_label' style='width: "+a.labelWidth+"px; text-align: "+c+";'>"+a.label+"</div>"},defaults:{template:function(a,b){return b.pb(a,"text")},labelWidth:80,s:28,nb:0},type_setter:function(a){return a},Z:function(){this.a.inputWidth?this.J().style.width=this.a.inputWidth-this.a.labelWidth-this.a.s+"px":this.J().style.width=this.j-this.a.labelWidth-this.a.s-this.a.nb+"px"},focus:function(){var a=this.d.getElementsByTagName("input")[0];
|
||||
a&&a.focus()},K:function(a){this.getInput().value=a},ab:function(){return this.getInput().value}},dhx.ui.button);
|
||||
dhx.protoUI({name:"toggle",defaults:{template:function(a,b){var c=a.options;b.Ba(c);var d=b.a.inputWidth/2||"auto",e=[c[0].width||d,c[1].width||d],f=b.qb(a,"toggle"),g="<input type='button' style='width: "+e[0]+"px;' value='"+a.options[0].label+"' />";g+="<input type='button' style='width: "+e[1]+"px;' value='"+a.options[1].label+"' />";return b.$b(f,g,a)},label:"",labelWidth:0,s:20},Z:function(){},Aa:function(a){this.setValue(a.value)},$a:function(){return this.d.getElementsByTagName("input")},
|
||||
K:function(a){var b=this.$a(),c=this.a.options;a==c[1].value?(b[0].className="dhx_inp_toggle_left_off",b[1].className="dhx_inp_toggle_right_on"):(b[0].className="dhx_inp_toggle_left_on",b[1].className="dhx_inp_toggle_right_off")},ab:function(){var a=this.$a(),b=this.a.options;return a[0].className=="dhx_inp_toggle_left_on"?b[0].value:b[1].value}},dhx.ui.text);
|
||||
dhx.protoUI({name:"input",defaults:{attributes:["maxlength","disabled","placeholder"],template:function(a,b){for(var c="<input",d=b.a.attributes,e=0;e<d.length;e++)a[d[e]]&&(c+=" "+d[e]+"='"+a[d[e]]+"'");c+=" type='"+(a.type||"text")+"'";c+="/>";return"<div class='dhx_el_input'>"+c+"</div>"},s:28,labelWidth:0}},dhx.ui.text);
|
||||
dhx.protoUI({name:"select",defaults:{template:function(a,b){var c=a.options;b.Ba(c);var d="<select";a.disabled&&(d+=" disabled='true'");d+=">";for(var e=0;e<c.length;e++)d+="<option"+(c[e].selected?" selected='true'":"")+(c[e].value?" value='"+c[e].value+"'":"")+">"+c[e].label+"</option>";d+="</select>";return"<div class='dhx_el_select'>"+d+"</div>"},labelWidth:0,nb:0,s:10},getInput:function(){return this.d.firstChild.firstChild}},dhx.ui.text);
|
||||
dhx.protoUI({name:"textarea",defaults:{template:function(a){return"<div class='dhx_el_textarea'><textarea class='dhx_inp_textarea' placeholder='"+(a.label||"")+"' style=''>"+(a.value||"")+"</textarea></div>"},cssContant:28},Z:function(){this.a.inputWidth?this.J().style.width=this.a.inputWidth-this.a.cssContant+"px":this.J().style.width=this.j-this.a.nb-this.a.cssContant+"px";this.a.inputHeight?this.J().style.height=this.a.inputHeight+"px":this.J().style.height=this.m-9+"px"},getInput:function(){return this.d.firstChild.firstChild},
|
||||
K:function(a){this.getInput().value=a},ab:function(){return this.getInput().value}},dhx.ui.text);
|
||||
dhx.protoUI({name:"counter",defaults:{template:function(a,b){var c=a.value||0,d=b.qb(a,"counter"),e="<input type='button' class='dhx_inp_counter_prev' value='\u25ac' />";e+="<div class='dhx_inp_counter_value' >"+c+"</div>";e+="<input type='button' class='dhx_inp_counter_next' value='+' />";return b.$b(d,e,a)},min:1,step:1,labelWidth:0,label:"",s:145},J:function(){return this.getInput().parentNode},getLabel:function(){return this.getInput().previousSibling||this.getInput().parentNode.lastChild},Z:function(){if(this.a.label&&
|
||||
!this.a.labelWidth){var a=this.getLabel();if(a)a.style.width=(this.a.inputWidth||this.j)-this.a.s+"px"}},K:function(a){this.getInput().nextSibling.innerHTML=a},getValue:function(){return(this.a.value||0)*1},next:function(a,b,c){a=a||1;this.kd(a,b,c)},prev:function(a,b,c){a=-1*(a||1);this.kd(a,b,c)},kd:function(a,b,c){var b=typeof b=="undefined"?-Infinity:b,c=typeof c=="undefined"?Infinity:c,d=this.getValue()+a;d>=b&&d<=c&&this.setValue(d)}},dhx.ui.text);
|
||||
dhx.protoUI({name:"checkbox",defaults:{template:function(a,b){var c=a.value?"dhx_inp_checkbox_on":"dhx_inp_checkbox_on hidden",d="<div class='dhx_inp_checkbox_border'><input type='button' class='"+c+"' value='' /></div>",e=b.qb(a,"checkbox");return b.$b(e,d,a)}},K:function(a){var b=this.getInput();b.className=a?"dhx_inp_checkbox_on":"dhx_inp_checkbox_on hidden"},toggle:function(){this.setValue(!this.getValue())},getLabel:function(){var a=this.getInput().parentNode;return a.nextSibling||a.previousSibling},
|
||||
getValue:function(){return this.a.value?1:0},J:function(){return this.getInput().parentNode.parentNode}},dhx.ui.counter);
|
||||
dhx.protoUI({name:"radio",defaults:{template:function(a,b){b.Ba(a.options);for(var c=[],d=0;d<a.options.length;d++){a.options[d].newline&&c.push("<div style='clear:both;'></div>");var e="<div radio_id='"+a.options[d].value+"' class='dhx_inp_radio_border'><input type='button' class='"+(a.options[d].value==a.value?"dhx_inp_radio_on":"dhx_inp_radio_on hidden")+"' value='' /></div>";a.label=a.options[d].label;var f=b.qb(a,"radio");a.labelPosition=="left"?c.push(f+e):c.push(e+f)}return"<div class='dhx_el_radio'><div>"+
|
||||
c.join("</div><div>")+"</div></div>"}},$getSize:function(){var a=dhx.ui.button.prototype.$getSize.call(this);if(this.a.options){for(var b=1,c=0;c<this.a.options.length;c++)this.a.options[c].newline&&b++;a[3]=Math.max(a[3],this.defaults.height*b)}return a},$a:function(){return this.d.getElementsByTagName("input")},K:function(a){for(var b=this.$a(),c=0;c<b.length;c++)b[c].className=b[c].parentNode.getAttribute("radio_id")==a?"dhx_inp_radio_on":"dhx_inp_radio_on hidden"},getValue:function(){return this.a.value}},
|
||||
dhx.ui.text);
|
||||
dhx.protoUI({name:"richselect",defaults:{template:function(a,b){return b.pb(a,"list",!0,!0)}},Y:function(a){a.popup||this.Cb("list",a);this.dc();this.Y=function(){}},options_setter:function(a){for(var b=this.a.data=[],c=0;c<a.length;c++){var d=a[c].value||a[c].label||a[c],e=a[c].label||a[c].value||a[c];b.push({id:d,value:e})}return a},Aa:function(a){this.Y(a);if(!dhx.isNotDefined(a.value)){this.setValue(a.value,{},a);var b=dhx.ui.get(a.popup.toString()),c=b.h,d=this;c.attachEvent("onXLE",dhx.bind(function(){this.setValue(this.a.value,
|
||||
{},a)},this))}},Cb:function(a,b){var c=dhx.extend({},b);delete c.align;delete c.height;delete c.width;delete c.template;c.view=a;c.id=(b.id||b.name)+"_"+a;c.width=c.popupWidth||290;var d=dhx.uid(),e={id:d,view:"popup",body:c};dhx.ui(e).hide();b.popup=d;this.dc()},dc:function(){var a=dhx.ui.get(this.a.popup);a.h.attachEvent("onItemClick",function(a){var c=dhx.ui.get(this.getParent().a.master);this.getParent().hide();c.setValue(a)})},getInput:function(){return this.d.firstChild.childNodes[0].childNodes[1]},
|
||||
K:function(a){var b=dhx.ui.get(this.a.popup).h,c=b.type?b.type.template(b.item(a)||a,b.type):a;this.a.value=a;this.a.text=c;this.name=="combo"?this.getInput().value=c.replace(/<[^>]*>/g,""):this.getInput().innerHTML=c},getValue:function(){return this.a.value}},dhx.ui.text);
|
||||
dhx.protoUI({name:"combo",defaults:{template:function(a,b){return b.pb(a,"combo")},filter:function(a,b){return a.value.toString().toLowerCase().indexOf(b.toLowerCase())===0?!0:!1}},Y:function(a){a.popup||this.Cb("list",a);this.dc();dhx.event(this.d,"keydown",function(b){var b=b||event,c=b.target||b.srcElement,d=dhx.ui.get(a.popup);window.clearTimeout(d.key_timer);var e=this;d.key_timer=window.setTimeout(function(){d.h.filter(function(a){return e.a.filter.apply(e,[a,c.value])});var a=dhx.ui.get(d.a.master);
|
||||
a.a.value=d.h.dataCount()==1&&d.h.type.template(d.h.item(d.h.first()))==c.value?d.h.first():""},200);d.show(c,d.h.a.align||"bottom",!0)},this);this.Y=function(){}},Aa:function(a){this.Y(a);dhx.isNotDefined(a.value)||this.setValue(a.value)}},dhx.ui.richselect);
|
||||
dhx.protoUI({name:"datepicker",defaults:{template:function(a,b){return b.pb(a,"list",!0,!0)}},Y:function(a){a.popup||this.Cb("calendar",a);var b=dhx.ui.get(a.popup);b.h.attachEvent("onDateSelect",function(a){var b=dhx.ui.get(this.getParent().a.master);this.getParent().hide();b.setValue(a)});this.Y=function(){}},Aa:function(a){this.Y(a);dhx.isNotDefined(a.value)||this.setValue(a.value)},K:function(a){var b=dhx.ui.get(this.a.popup.toString()),c=b.h;typeof a=="string"&&a&&(a=(this.a.dateFormat||dhx.i18n.dateFormatDate)(a));
|
||||
c.selectDate(a,!0);this.a.value=a?c.config.date:"";this.getInput().innerHTML=a?(this.a.dateFormatStr||dhx.i18n.dateFormatStr)(this.a.value):""},dateFormat_setter:function(a){this.a.dateFormatStr=dhx.Date.dateToStr(a);return dhx.Date.strToDate(a)},getValue:function(){return this.a.value||null}},dhx.ui.richselect);
|
||||
dhx.ValidateData={validate:function(a){var b=!0,c=this.a.rules;if(c){var d=c.$obj;!a&&this.getValues&&(a=this.getValues());if(d&&!d.call(this,a))return!1;var e=c.$all,f;for(f in c)f.indexOf("$")!==0&&(c[f].call(this,a[f],a,f)&&(!e||e.call(this,a[f],a,f))?this.callEvent("onValidationSuccess",[f,a])&&this.tc&&this.tc(f,a):(b=!1,this.callEvent("onValidationError",[f,a])&&this.Lc&&this.Lc(f,a)))}return b}};
|
||||
dhx.rules={isNumber:function(a){return parseFloat(a)==a},isNotEmpty:function(a){return a=="0"||a}};
|
||||
dhx.RenderStack={$init:function(){this.F=document.createElement("DIV");this.data.attachEvent("onIdChange",dhx.bind(this.Zb,this));this.attachEvent("onItemClick",this.Dd);if(!this.types)this.types={"default":this.type},this.type.name="default";this.type=dhx.copy(this.types[this.type.name])},customize:function(a){dhx.Type(this,a)},type_setter:function(a){this.types[a]?(this.type=dhx.copy(this.types[a]),this.type.css&&(this.g.className+=" "+this.type.css)):this.customize(a);return a},template_setter:function(a){this.type.template=
|
||||
dhx.Template(a)},xa:function(a){this.callEvent("onItemRender",[a]);return this.type.templateStart(a,this.type)+(a.$template?this.type["template"+a.$template]:this.type.template)(a,this.type)+this.type.templateEnd(a,this.type)},ld:function(a){this.F.innerHTML=this.xa(a);return this.F.firstChild},Zb:function(a,b){var c=this.pa(a);c&&(c.setAttribute(this.ma,b),this.B[b]=this.B[a],delete this.B[a])},Dd:function(){if(this.a.click){var a=dhx.toFunctor(this.a.click);a&&a.call&&a.apply(this,arguments)}},
|
||||
pa:function(a){if(this.B)return this.B[a];this.B={};for(var b=this.d.childNodes,c=0;c<b.length;c++){var d=b[c].getAttribute(this.ma);d&&(this.B[d]=b[c])}return this.pa(a)},locate:function(a){return dhx.html.locate(a,this.ma)},showItem:function(a){var b=this.pa(a);if(b&&this.scrollTo){var c=Math.max(0,b.offsetLeft-this.d.offsetLeft),d=Math.max(0,b.offsetTop-this.d.offsetTop);this.scrollTo(c,d);this.bd&&this.bd(a)}},render:function(a,b,c){if(this.isVisible(this.a.id))if(a){var d=this.pa(a);switch(c){case "update":if(!d)break;
|
||||
var e=this.B[a]=this.ld(b);dhx.html.insertBefore(e,d);dhx.html.remove(d);break;case "delete":if(!d)break;dhx.html.remove(d);delete this.B[a];break;case "add":e=this.B[a]=this.ld(b);dhx.html.insertBefore(e,this.pa(this.data.next(a)),this.d);break;case "move":this.render(a,b,"delete"),this.render(a,b,"add")}}else if(this.callEvent("onBeforeRender",[this.data]))(this.De||this.d).innerHTML=this.data.getRange().map(this.xa,this).join(""),this.B=null,this.callEvent("onAfterRender",[])}};
|
||||
dhx.protoUI({name:"proto",$init:function(){this.data.provideApi(this,!0);this.d=this.g;this.data.attachEvent("onStoreUpdated",dhx.bind(function(){this.render.apply(this,arguments)},this))},$setSize:function(){dhx.ui.view.prototype.$setSize.apply(this,arguments)&&this.render()}},dhx.RenderStack,dhx.DataLoader,dhx.ui.view,dhx.EventSystem,dhx.Settings);
|
||||
dhx.Values={$init:function(){this.elements={}},focus:function(a){a?this.elements[a].focus():this.first().focus()},setValues:function(a){if(this.isVisible(this.a.id)){this.sd=dhx.copy(a);for(var b in this.elements)this.elements[b]&&!dhx.isNotDefined(a[b])&&this.elements[b].setValue(a[b]);this.callEvent("onChange",[])}else this.fc=a},getValues:function(){var a=this.sd?dhx.copy(this.sd):{},b;for(b in this.elements)a[b]=this.elements[b].getValue();return a},clear:function(){var a={},b;for(b in this.elements)this.elements[b].wd&&
|
||||
(a[b]=this.elements[b].a.defaultValue||"");this.setValues(a)},mb:function(a,b){var c=this.data.driver,d=c.getRecords(c.toObject(a,b))[0];this.setValues(c?c.getDetails(d):a);this.callEvent("onXLE",[])},Lc:function(a){dhx.html.addCss(this.elements[a].d.firstChild,"invalid")},tc:function(a){dhx.html.removeCss(this.elements[a].d.firstChild,"invalid")}};
|
||||
dhx.protoUI({name:"toolbar",defaults:{type:"MainBar"},Ce:!0,Db:44,$init:function(a){this.g.style.border="1px solid #AEAEAE";this.Vc(a)},Vc:function(a){this.g.className+=" dhx_toolbar";if(a.elements)this.Q=a.elements,this.r=!1;delete a.elements;dhx.sa=this},$getSize:function(){var a=dhx.ui.baselayout.prototype.$getSize.call(this);if(a[3]>0&&(!this.r||!this.a.scroll))this.a.height=a[3];if(a[1]>0&&(this.r||!this.a.scroll))this.a.width=a[1];a=dhx.ui.view.prototype.$getSize.call(this);if(a[3]<=0&&this.Db>
|
||||
0)a[3]=this.Db,a[2]=0;return a},$setSize:function(a,b){dhx.ui.view.prototype.$setSize.apply(this,arguments);dhx.ui.baselayout.prototype.$setSize.call(this,this.j,this.m)},render:function(){if(this.isVisible(this.a.id)&&this.fc)this.setValues(this.fc),this.fc=null},refresh:function(){this.render()},type_setter:function(a){this.g.className+=" dhx_"+a.toLowerCase()}},dhx.Scrollable,dhx.AtomDataLoader,dhx.Values,dhx.ui.baselayout,dhx.EventSystem,dhx.ValidateData);
|
||||
dhx.protoUI({name:"form",defaults:{scroll:!0},Db:-1,Vc:function(a){this.g.className+=" dhx_form";if(a.elements)this.Q=a.elements,this.r=!0;delete a.elements;dhx.sa=this},type_setter:function(){}},dhx.ui.toolbar);
|
||||
dhx.MouseEvents={$init:function(){this.on_click&&dhx.event(this.g,"click",this.me,this);this.on_context&&dhx.event(this.g,"contextmenu",this.ne,this);this.on_dblclick&&dhx.event(this.g,"dblclick",this.oe,this);this.on_mouse_move&&(dhx.event(this.g,"mousemove",this.Rc,this),dhx.event(this.g,dhx.env.isIE?"mouseleave":"mouseout",this.Rc,this))},me:function(a){return this.Ja(a,this.on_click,"ItemClick")},oe:function(a){return this.Ja(a,this.on_dblclick,"ItemDblClick")},ne:function(a){if(this.Ja(a,this.on_context,
|
||||
"BeforeContextMenu"))return this.Ja(a,{},"AfterContextMenu"),dhx.html.preventEvent(a)},Rc:function(a){dhx.env.isIE&&(a=document.createEventObject(event));this.Nc&&window.clearTimeout(this.Nc);this.callEvent("onMouseMoving",[a]);this.Nc=window.setTimeout(dhx.bind(function(){a.type=="mousemove"?this.pe(a):this.qe(a)},this),500)},pe:function(a){this.Ja(a,this.on_mouse_move,"MouseMove")||this.callEvent("onMouseOut",[a||event])},qe:function(a){this.callEvent("onMouseOut",[a||event])},Ja:function(a,b,c){for(var a=
|
||||
a||event,d=a.target||a.srcElement,e="",f=null,g=!1;d&&d.parentNode;){if(!g&&d.getAttribute&&(f=d.getAttribute(this.ma))){d.getAttribute("userdata")&&this.callEvent("onLocateData",[f,d]);if(!this.callEvent("on"+c,[f,a,d]))return;g=!0}if(e=d.className)if(e=e.split(" "),e=e[0]||e[1],b[e]){var h=b[e].call(this,a,f||dhx.html.locate(a,this.ma),d);if(typeof h!="undefined"&&h!==!0)return}d=d.parentNode}return g}};
|
||||
dhx.SelectionModel={$init:function(){this.i=dhx.toArray();this.data.attachEvent("onStoreUpdated",dhx.bind(this.Pd,this));this.data.attachEvent("onStoreLoad",dhx.bind(this.Od,this));this.data.attachEvent("onAfterFilter",dhx.bind(this.Nd,this));this.data.attachEvent("onChangeId",dhx.bind(this.Zd,this))},Zd:function(a,b){for(var c=this.i.length-1;c>=0;c--)this.i[c]==a&&(this.i[c]=b)},Nd:function(){for(var a=this.i.length-1;a>=0;a--){if(this.data.indexById(this.i[a])<0)var b=this.i[a];var c=this.item(b);
|
||||
c&&delete c.$selected;this.i.splice(a,1);this.callEvent("onSelectChange",[b])}},Pd:function(a,b,c){if(c=="delete")this.i.remove(a);else if(!this.data.dataCount()&&!this.data.p)this.i=dhx.toArray()},Od:function(){this.a.select&&this.data.each(function(a){a.$selected&&this.select(a.id)},this)},ub:function(a,b,c){if(!c&&!this.callEvent("onBeforeSelect",[a,b]))return!1;this.data.item(a).$selected=b;c?c.push(a):(b?this.i.push(a):this.i.remove(a),this.Vb(a));return!0},select:function(a,b,c){if(!a)return this.selectAll();
|
||||
if(dhx.isArray(a))for(var d=0;d<a.length;d++)this.select(a[d],b,c);else if(this.data.exists(a)){if(c&&this.i.length)return this.selectAll(this.i[this.i.length-1],a);if(!b&&(this.i.length!=1||this.i[0]!=a))this.fd=!0,this.unselectAll(),this.fd=!1;this.isSelected(a)?b&&this.unselect(a):this.ub(a,!0)&&this.callEvent("onAfterSelect",[a])}},unselect:function(a){if(!a)return this.unselectAll();this.isSelected(a)&&this.ub(a,!1)},selectAll:function(a,b){var c,d=[];c=a||b?this.data.getRange(a||null,b||null):
|
||||
this.data.getRange();c.each(function(a){var b=this.data.item(a.id);b.$selected||(this.i.push(a.id),this.ub(a.id,!0,d));return a.id},this);this.Vb(d)},unselectAll:function(){var a=[];this.i.each(function(b){this.ub(b,!1,a)},this);this.i=dhx.toArray();this.Vb(a)},isSelected:function(a){return this.i.find(a)!=-1},getSelected:function(a){switch(this.i.length){case 0:return a?[]:"";case 1:return a?[this.i[0]]:this.i[0];default:return[].concat(this.i)}},ee:function(a){return a.length>100||a.length>this.data.dataCount/
|
||||
2},Vb:function(a){typeof a!="object"&&(a=[a]);if(a.length){if(this.ee(a))this.data.refresh();else for(var b=0;b<a.length;b++)this.render(a[b],this.data.item(a[b]),"update");this.fd||this.callEvent("onSelectChange",[a])}}};
|
||||
dhx.TreeStore={$init:function(){this.branch={0:[]}},clearAll:function(){this.branch={0:[]};dhx.DataStore.prototype.clearAll.call(this)},prevSibling:function(a){var b=this.branch[this.item(a).$parent],c=dhx.PowerArray.find.call(b,a)-1;return c>=0?b[c]:null},nextSibling:function(a){var b=this.branch[this.item(a).$parent],c=dhx.PowerArray.find.call(b,a)+1;return c<b.length?b[c]:null},parent:function(a){return this.item(a).$parent},firstChild:function(a){var b=this.branch[a];return b&&b.length?b[0]:null},
|
||||
hasChild:function(a,b){var c=this.branch[a];if(c&&c.length)for(var d=0;d<c.length;d++){if(c[d]==b)return!0;if(this.hasChild(c[d],b))return!0}return!1},branchIndex:function(a,b){var c=this.branch[a];return dhx.PowerArray.find.call(c,b)},extraParser:function(a,b,c){a.$parent=b||0;a.$level=c||1;this.branch[a.$parent]||(this.branch[a.$parent]=[]);this.branch[a.$parent].push(a.id);if(!a.item)return a.$count=0;dhx.isArray(a.item)?a.$count=a.item.length:(a.item=[a.item],a.$count=1);for(var d=0;d<a.item.length;d++){var e=
|
||||
a.item[d];this.pull[this.id(e)]=e;this.extraParser(e,a.id,a.$level+1)}delete a.item},provideApi:function(a,b){for(var c="prevSibling,nextSibling,parent,firstChild,hasChild,branchIndex".split(","),d=0;d<c.length;d++)a[c[d]]=dhx.methodPush(this,c[d]);dhx.DataStore.prototype.provideApi.call(this,a,b)},getTopRange:function(){return dhx.toArray([].concat(this.branch[0])).map(function(a){return this.item(a)},this)},eachChild:function(a,b){if(this.branch[a])return dhx.PowerArray.each.call(this.branch[a],
|
||||
b)},add:function(a,b,c){this.branch[c||0]=this.order=dhx.toArray(this.branch[c||0]);(c=this.item(c||0))&&c.$count++;a.$count=0;a.$level=c?c.$level+1:1;a.$parent=c?c.id:0;return dhx.DataStore.prototype.add.call(this,a,b)},remove:function(a){var b=this.item(a),c=b.$parent||0;this.branch[c]=this.order=dhx.toArray(this.branch[c]);c&&this.item(c).$count--;return dhx.DataStore.prototype.remove.call(this,a)},serialize:function(a){for(var b=this.branch[a||0],c=[],d=0;d<b.length;d++){var e=this.pull[b[d]];
|
||||
if(e.$count)e=dhx.copy(e),e.item=this.serialize(b[d]);c.push(e)}return c},groupBy:function(a,b,c,d,e){if(c===!0){var f={},g=dhx.copy(a),h=g.pop(),i={},j;for(j in b){var k=b[j],o=k[h];if(typeof i[o]==="undefined"){j=dhx.uid();var m={id:j,text:o,$count:0,$level:e,$parent:d};i[o]=j;f[j]=[];this.pull[j]=m;this.branch[d].push(j);this.branch[j]=[]}else j=i[o];f[j].push(k);g.length===0&&this.branch[j].push(k.id)}for(var l in f)this.pull[l].$count=f[l].length,g.length>0&&this.groupBy(g,f[l],!0,l,e+1)}else{var n=
|
||||
arguments,g=[];this.branch={0:[]};for(l=n.length-1;l>=0;l--)g.push(n[l]);this.groupBy(g,this.pull,!0,"0",0);this.refresh()}}};dhx.animate=function(a,b){if(dhx.isArray(a))for(var c=0;c<a.length;c++){if(b.type=="slide"){if(b.subtype=="out"&&c===0)continue;if(b.subtype=="in"&&c==1)continue}if(b.type=="flip"){var d=dhx.copy(b);if(c===0)d.type="flipback";if(c==1)d.callback=null;dhx.animate(a[c],d)}else dhx.animate(a[c],b)}else{var e=dhx.toNode(a);e.cb?dhx.animate.end(e,b):dhx.animate.start(e,b)}};
|
||||
dhx.animate.end=function(a,b){a.style[dhx.env.transformPrefix+"TransitionDuration"]="1ms";a.cb=null;dhx.td&&window.clearTimeout(dhx.td);dhx.td=dhx.delay(dhx.animate,dhx,[a,b],10)};dhx.animate.isSupported=function(){return dhx.env.transform&&dhx.env.transition};
|
||||
dhx.animate.formLine=function(a,b,c){var d=c.direction;b.parentNode.style.position="relative";b.style.position="absolute";a.style.position="absolute";d=="top"||d=="bottom"?(a.style.left="0px",a.style.top=(d=="top"?1:-1)*b.offsetHeight+"px"):(a.style.top="0px",a.style.left=(d=="left"?1:-1)*b.offsetWidth+"px");b.parentNode.appendChild(a);if(c.type=="slide"&&c.subtype=="out")a.style.left=0,a.style.top=0,b.parentNode.removeChild(b),a.parentNode.appendChild(b);return[a,b]};
|
||||
dhx.animate.breakLine=function(a){dhx.html.remove(a[1]);dhx.animate.clear(a[0]);dhx.animate.clear(a[1]);a[0].style.position=""};dhx.animate.clear=function(a){a.style[dhx.env.transformPrefix+"Transform"]="";a.style[dhx.env.transformPrefix+"Transition"]="";a.style.top=a.style.left=""};
|
||||
dhx.animate.start=function(a,b){typeof b=="string"&&(b={type:b});var b=dhx.Settings.Ia(b,{type:"slide",delay:"0",duration:"500",timing:"ease-in-out",x:0,y:0}),c=dhx.env.transformPrefix,d=a.cb=b;switch(d.type=="slide"&&d.direction){case "right":d.x=a.offsetWidth;break;case "left":d.x=-a.offsetWidth;break;case "top":d.y=-a.offsetHeight;break;default:d.y=a.offsetHeight}if(d.type=="flip"||d.type=="flipback"){var e=[0,0],f="scaleX";d.subtype=="vertical"?(e[0]=20,f="scaleY"):e[1]=20;if(d.direction=="right"||
|
||||
d.direction=="bottom")e[0]*=-1,e[1]*=-1}var g=d.duration+"ms "+d.timing+" "+d.delay+"ms",h=c+"TransformStyle: preserve-3d;",i="",j="";switch(d.type){case "fade":i="opacity "+g;h="opacity: 0;";break;case "show":i="opacity "+g;h="opacity: 1;";break;case "flip":g=d.duration/2+"ms "+d.timing+" "+d.delay+"ms";j="skew("+e[0]+"deg, "+e[1]+"deg) "+f+"(0.00001)";i="all "+g;break;case "flipback":d.delay+=d.duration/2;g=d.duration/2+"ms "+d.timing+" "+d.delay+"ms";a.style[c+"Transform"]="skew("+-1*e[0]+"deg, "+
|
||||
-1*e[1]+"deg) "+f+"(0.00001)";a.style.left="0";j="skew(0deg, 0deg) "+f+"(1)";i="all "+g;break;case "slide":var k=d.x+"px",o=d.y+"px",j=dhx.env.translate+"("+k+", "+o+(dhx.env.translate=="translate3d"?", 0":"")+")",i=dhx.env.transformCSSPrefix+"transform "+g}dhx.delay(function(){a.style[c+"Transition"]=i;dhx.delay(function(){h&&(a.style.cssText+=h);j&&(a.style[c+"Transform"]=j);var b=!1,e=dhx.event(a,dhx.env.transitionEnd,function(c){a.cb=null;d.callback&&d.callback.call(d.master||window,a,d,c);b=
|
||||
!0;dhx.eventRemove(e)});window.setTimeout(function(){if(!b)a.cb=null,d.callback&&d.callback.call(d.master||window,a,d),b=!0,dhx.eventRemove(e)},(d.duration*1+d.delay*1)*1.3)})})};
|
||||
dhx.CarouselPanel={Wb:function(){var a,b,c,d;a=this.a.panel;dhx.html.remove(this.P);b="z-index:"+dhx.ui.zIndex()+";";if(a.align=="bottom"||a.align=="top")b+="height:"+a.size+"px; left:0px;",c=0,a.align=="bottom"&&(c=this.m-this.a.panel.size),b+="top:"+c+"px";else if(a.align=="right"||a.align=="left")b+="width:"+a.size+"px;top:0px;",d=0,a.align=="right"&&(d=this.j-this.a.panel.size),b+="left:"+d+"px";this.P=dhx.html.create("DIV",{"class":"dhx_carousel_panel",style:b},"");this.b.appendChild(this.P);
|
||||
this.Xb()},Xb:function(){var a,b;b=this.a.panel;this.P?this.Hd():this.Wb();var c=this.c?this.c.length:this.data.order.length;if(c>1){for(var d=0;d<c;d++)a=dhx.html.create("DIV",{"class":"dhx_item dhx_carousel_"+(d==this.l?"active":"inactive"),style:b.align=="left"||b.align=="right"?"float:none;":""},""),this.P.appendChild(a);var e=c*this.a.panel.itemSize;b.align=="bottom"||b.align=="top"?(this.P.style.left=(this.j-e)/2+this.b.scrollLeft+"px",this.P.style.width=e+"px"):this.P.style.top=(this.m-e)/
|
||||
2+this.b.scrollTop+"px"}},Hd:function(){if(this.P)for(var a=this.P.childNodes,b=a.length-1;b>=0;b--)dhx.html.remove(a[b])}};
|
||||
dhx.protoUI({name:"list",$init:function(){this.data.provideApi(this,!0)},defaults:{select:!1,scroll:!0},ma:"dhx_l_id",on_click:{dhx_list_item:function(a,b){if(this.a.select)this.ra=!0,this.a.select=="multiselect"?this.select(b,a.ctrlKey,a.shiftKey):this.select(b),this.ra=!1}},$getSize:function(){if(this.type.width!="auto")this.a.width=this.type.width+(this.type.padding+this.type.margin)*2;if(this.a.yCount)this.a.height=(this.type.height+(this.type.padding+this.type.margin)*2+1)*(this.a.yCount=="auto"?
|
||||
this.dataCount():this.a.yCount);return dhx.ui.view.prototype.$getSize.call(this)},$setSize:function(){dhx.ui.view.prototype.$setSize.apply(this,arguments)},type:{css:"",widthSize:function(a,b){return b.width+(b.width>-1?"px":"")},heightSize:function(a,b){return b.height+(b.height>-1?"px":"")},template:dhx.Template("#value#"),width:"auto",height:22,margin:0,padding:10,border:1,templateStart:dhx.Template("<div dhx_l_id='#id#' class='dhx_list_item dhx_list_{common.css}_item{obj.$selected?_selected:}' style='width:{common.widthSize()}; height:{common.heightSize()}; padding:{common.padding}px; margin:{common.margin}px; overflow:hidden;'>"),
|
||||
templateEnd:dhx.Template("</div>")}},dhx.MouseEvents,dhx.SelectionModel,dhx.Scrollable,dhx.ui.proto);
|
||||
dhx.protoUI({name:"grouplist",defaults:{animate:{}},$init:function(){dhx.extend(this.data,dhx.TreeStore,!0);this.data.provideApi(this,!0);this.data.attachEvent("onClearAll",dhx.bind(this.Qc,this));this.b.className+=" dhx_grouplist";this.Qc()},Qc:function(){this.aa=[];this.z=[]},on_click:{dhx_list_item:function(a,b){if(this.oa)return!1;for(var c=0;c<this.z.length;c++)if(this.z[c]==b){for(var d=c;d<this.z.length;d++)this.data.item(this.z[d]).$template="";c?(this.aa=this.data.branch[this.z[c-1]],this.z.splice(c)):
|
||||
(this.aa=this.data.branch[0],this.z=[]);this.Ic=!1;return this.render()}var e=this.item(b);if(e.$count)return this.Ic=!0,this.z.push(b),e.$template="Back",this.aa=this.data.branch[e.id],this.render();else if(this.a.select)this.ra=!0,this.a.select=="multiselect"?this.select(b,a.ctrlKey,a.shiftKey):this.select(b),this.ra=!1}},render:function(a,b,c,d){if(this.oa)return dhx.delay(this.render,this,arguments,100);for(var e=0;e<this.aa.length;e++)this.data.item(this.aa[e]).$template="";this.data.order=this.z.length?
|
||||
dhx.toArray([].concat(this.z).concat(this.aa)):dhx.toArray([].concat(this.data.branch[0]));if(this.callEvent("onBeforeRender",[this.data])){if(this.ra||!this.d.innerHTML||!dhx.animate.isSupported()||!this.a.animate||this.xe==this.z.length)dhx.RenderStack.render.apply(this,arguments);else{var f=this.d.cloneNode(!1);f.innerHTML=this.data.getRange().map(this.xa,this).join("");var g=dhx.extend({},this.a.animate);g.direction=this.Ic?"left":"right";var h=dhx.animate.formLine(f,this.d,g);g.master=this;g.callback=
|
||||
function(){this.d=f;dhx.animate.breakLine(h);this.B=g.master=g.callback=null;this.oa=!1;this.callEvent("onAfterRender",[])};this.oa=!0;dhx.animate(h,g)}this.xe=this.z.length}},templateBack_setter:function(a){this.type.templateBack=dhx.Template(a)},templateItem_setter:function(a){this.type.templateItem=dhx.Template(a)},templateGroup_setter:function(a){this.type.templateGroup=dhx.Template(a)},type:{template:function(a,b){return a.$count?b.templateGroup(a,b):b.templateItem(a,b)},css:"group",templateStart:dhx.Template("<div dhx_l_id='#id#' class='dhx_list_item dhx_list{obj.$count?_group:_item}{obj.$template?_back:}{obj.$selected?_selected:}' style='width:{common.width}px; height:{common.height}px; padding:{common.padding}px; margin:{common.margin}px; overflow:hidden;'>"),
|
||||
templateBack:dhx.Template("< #value#"),templateItem:dhx.Template("#value#"),templateGroup:dhx.Template("#value#"),templateEnd:function(a){var b="";a.$count&&(b+="<div class='dhx_arrow_icon'></div>");b+="</div>";return b}},showItem:function(a){var b,c;if(a&&(b=this.item(a),c=b.$parent,b.$count))c=b.id;this.aa=this.data.branch[c||0];for(this.z=[];c;)this.item(c).$template="Back",this.z.unshift(c),c=this.item(c).$parent;this.ra=!0;this.render();this.ra=!1;dhx.RenderStack.showItem.call(this,a)}},dhx.ui.list);
|
||||
dhx.Type(dhx.ui.grouplist,{});
|
||||
dhx.protoUI({name:"pagelist",defaults:{scroll:"x",panel:!1,scrollOffset:0},Yd:!0,$init:function(a){this.b.className+=" dhx_pagelist";a.scroll=a.scroll=="y"?"y":"x";this.type.layout=a.scroll;this.attachEvent("onAfterRender",this.Ie);this.$ready.push(this.zb);this.l=0},zb:function(){if(this.a.scroll=="x")this.d.style.height="100%";this.type.layout=this.a.scroll;this.attachEvent("onAfterScroll",this.Ld)},Ie:function(){if(this.a.scroll=="x")this.d.style.width=(this.type.width+(this.type.padding+this.type.margin)*
|
||||
2+this.type.border)*this.dataCount()+"px";this.a.panel&&this.Wb()},panel_setter:function(a){a&&(this.b.className+=" hidden_scroll",a===!0&&(a={}),this.Ia(a,{size:16,itemSize:16,align:"bottom"}));return a},bd:function(a){var b=this.indexById(a);if(typeof b!="undefined"&&this.a.panel)this.l=b,this.Xb()},getActive:function(){return this.l?this.data.order[this.l]:this.first()},Ld:function(a){var b=(this.a.scroll=="y"?this.type.height:this.type.width)+(this.type.padding+this.type.margin)*2+this.type.border,
|
||||
c=this.a.scroll=="y"?this.d.scrollHeight-this.m:this.d.scrollWidth-this.j,d;this.a.scroll=="y"?(d=Math.round(a.f/b),a.f=d*b,a.f=this.uc(a.f,c)):(d=Math.round(a.e/b),a.e=d*b,a.e=this.uc(a.e,c));this.l=-d;this.a.panel&&this.Xb();return!0},uc:function(a,b){var c=this.a.scrollOffset;if(c&&Math.abs(a)>c){var d=dhx.Touch.A[dhx.Touch.H]>dhx.Touch.w[dhx.Touch.H];a+=d?c:1-c}Math.abs(a)>b&&(a=-b);return a},$getSize:function(){if(this.a.scroll=="y"){if(this.type.width!="auto")this.a.width=this.type.width+(this.type.padding+
|
||||
this.type.margin)*2+this.type.border;if(this.a.yCount)this.a.height=(this.type.height+(this.type.padding+this.type.margin)*2+this.type.border)*(this.a.yCount=="auto"?this.dataCount():this.a.yCount)}else if(this.type.height!="auto")this.a.height=this.type.height+(this.type.padding+this.type.margin)*2+this.type.border;return dhx.ui.view.prototype.$getSize.call(this)},$setSize:function(a,b){if(dhx.ui.view.prototype.$setSize.apply(this,arguments)){if(this.type.fullScreen)this.type.width=this.j,this.type.height=
|
||||
this.m,this.type.padding=0,this.render();this.a.panel&&this.Wb()}},type:{templateStart:function(a,b){var c="dhx_list_item dhx_list_"+b.css+"_item"+(a.$selected?"_selected":""),d="width:"+b.width+"px; height:"+b.height+"px; padding:"+b.padding+"px; margin:"+b.margin+"px; overflow:hidden;"+(b.layout&&b.layout=="x"?"float:left;":"");return"<div dhx_l_id='"+a.id+"' class='"+c+"' style='"+d+"'>"}}},dhx.ui.list,dhx.CarouselPanel);
|
||||
dhx.protoUI({name:"multiview",defaults:{animate:{}},$init:function(){this.l=0;this.r=1;this.b.style.position="relative";this.b.className+=" dhx_multiview";this.M=[]},xd:function(a,b){var c=dhx.ui.get(a);if(!c.La)c.rb=[],c.La={};c.La[b]||(c.La[b]=!0,c.rb.push(b))},Yb:function(a){var b=dhx.ui.get(a);this.M[this.M.length-2]!=a?(this.M.length==10&&this.M.splice(0,1),this.M.push(a)):this.M.splice(this.M.length-1,1);if(b.La){for(var c=0;c<b.rb.length;c++)dhx.ui.get(b.rb[c]).render();b.rb=[];b.La={}}},T:function(a){for(var a=
|
||||
a||this.Q,b=0;b<a.length;b++)a[b].k=this.a.k||{top:1,bottom:1,left:1,right:1};dhx.ui.baselayout.prototype.T.call(this,a);for(b=1;b<this.c.length;b++)dhx.html.remove(this.c[b].b);for(b=0;b<a.length;b++){var c=this.c[b];if(!c.c||c.Ce){var d=c.a.k;if(d.top)c.b.style.borderTopWidth="0px";if(d.left)c.b.style.borderLeftWidth="0px";if(d.right)c.b.style.borderRightWidth="0px";if(d.bottom)c.b.style.borderBottomWidth="0px"}}this.Yb(this.getActive())},cells_setter:function(a){this.Q=a},Ud:function(a,b){return a<
|
||||
b?"right":"left"},Ma:function(a,b){if(this.oa)return dhx.delay(this.Ma,this,[a],100);for(var c=-1,d=0;d<this.c.length;d++)if(this.c[d]==a){c=d;break}if(!(c<0||c==this.l)){var e=this.c[this.l]?this.c[this.l].config.id:null,f=this.c[c]?this.c[c].config.id:null;if((b||typeof b=="undefined")&&dhx.animate.isSupported()&&this.a.animate){var g=dhx.extend({},this.a.animate);g.direction=this.Ud(c,this.l);var g=dhx.Settings.Ia(b||{},g),h=dhx.animate.formLine(this.c[c].b,this.c[this.l].b,g);this.c[c].$getSize();
|
||||
this.c[c].$setSize(this.j,this.m);g.callback=function(){dhx.animate.breakLine(h);this.oa=!1;g.master=g.callback=null};g.master=this;this.l=c;this.Yb(this.getActive());dhx.animate(h,g);this.oa=!0}else dhx.html.remove(this.c[this.l].b),this.l=c,this.c[this.l].$getSize(),this.c[this.l].$setSize(this.j,this.m),this.Yb(this.getActive()),this.b.appendChild(this.c[d].b);this.callEvent("onViewChange",[e,f])}},$getSize:function(){var a=this.c[this.l].$getSize();if(this.a.height>-1)a[3]=this.a.height,a[2]=
|
||||
0;if(this.a.width>-1)a[1]=this.a.width,a[0]=0;a[0]&&(a[1]=0);a[2]&&(a[3]=0);return a},$setSize:function(a,b){dhx.ui.baseview.prototype.$setSize.call(this,a,b);this.c[this.l].$setSize(a,b)},isVisible:function(a,b){return b&&b!=this.getActive()?(a&&this.xd(b,a),!1):dhx.ui.view.prototype.isVisible.call(this,a,this.a.id)},getActive:function(){return this.c.length?this.c[this.l].a.id:null},back:function(a){a=a||1;if(this.callEvent("onBeforeBack",[this.getActive(),a])&&this.M.length>a){var b=this.M[this.M.length-
|
||||
a-1];dhx.ui.get(b).show();return b}return null}},dhx.ui.baselayout,dhx.EventSystem);dhx.html.addMeta=function(a,b){document.getElementsByTagName("head").item(0).appendChild(dhx.html.create("meta",{name:a,content:b}))};
|
||||
(function(){var a=function(){var a=!!(window.orientation%180);if(dhx.ui.orientation!==a)dhx.ui.orientation=a,dhx.callEvent("onRotate",[a])};dhx.ui.orientation=!!((dhx.isNotDefined(window.orientation)?90:window.orientation)%180);dhx.event(window,"onorientationchange"in window?"orientationchange":"resize",a);dhx.ui.fullScreen=function(){dhx.html.addMeta("apple-mobile-web-app-capable","yes");dhx.html.addMeta("viewport","initial-scale = 1.0, maximum-scale = 1.0, user-scalable = no");if(dhx.env.touch){var b=
|
||||
document.body.offsetHeight,c=navigator.userAgent.indexOf("iPhone")!=-1,d=c&&(b==356||b==208||b==306||b==158),e=function(){if(c)dhx.ui.orientation?(b=480,e=d?268:300):(b=320,e=d?416:460);else{document.body.style.width=document.body.style.height="1px";document.body.style.overflow="hidden";var a=window.outerWidth/window.innerWidth,b=window.outerWidth/a,e=window.outerHeight/a}document.body.style.height=e+"px";document.body.style.width=b+"px";dhx.ui.yc=!1;dhx.ui.resize();dhx.delay(function(){window.scrollTo(0,
|
||||
1)})},f=function(){dhx.ui.yc=!0;dhx.env.isSafari?e():dhx.delay(e,null,[],500)};dhx.attachEvent("onClick",function(a){a.target.tagName=="INPUT"||a.target.tagName=="TEXTAREA"||a.target.tagName=="SELECT"||(d&&window.innerHeight<416||!d&&window.innerHeight<window.outerHeight)&&window.scrollTo(0,1)});dhx.attachEvent("onRotate",f);a();dhx.delay(f)}}})();dhx.math={};dhx.math.Ve="0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F".split(",");
|
||||
dhx.math.toHex=function(a,b){for(var a=parseInt(a,10),c="";a>0;)c=this.Ve[a%16]+c,a=Math.floor(a/16);for(;c.length<b;)c="0"+c;return c};dhx.math.toFixed=function(a){return a<10?"0"+a:a};
|
||||
dhx.i18n={dateFormat:"%d.%m.%Y",timeFormat:"%H:%i",longDateFormat:"%l, %d %F %Y",fullDateFormat:"%d-%m-%Y %H:%i",groupDelimiter:".",groupSize:3,decimalDelimeter:",",decimalSize:2,setLocale:function(){for(var a=["fullDateFormat","timeFormat","dateFormat","longDateFormat"],b=0;b<a.length;b++){var c=a[b];dhx.i18n[c+"Str"]=dhx.Date.dateToStr(dhx.i18n[c]);dhx.i18n[c+"Date"]=dhx.Date.strToDate(dhx.i18n[c])}}};
|
||||
dhx.Number={format:function(a,b){var b=b||dhx.i18n,a=parseFloat(a),c=a.toFixed(b.decimalSize).toString(),c=c.split("."),d="",e=b.groupSize,f=c[0].length;do{f-=e;var g=f>0?c[0].substr(f,e):c[0].substr(0,e+f),d=g+(d?b.groupDelimiter+d:"")}while(f>0);return d+b.decimalDelimeter+c[1]},numToStr:function(a){return function(b){return dhx.Number.format(b,a)}}};
|
||||
dhx.Date={Locale:{month_full:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),month_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),day_full:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(",")},weekStart:function(a){var b=a.getDay();this.config.start_on_monday&&(b===0?b=6:b--);return this.date_part(this.add(a,-1*b,"day"))},monthStart:function(a){a.setDate(1);return this.date_part(a)},
|
||||
yearStart:function(a){a.setMonth(0);return this.month_start(a)},dayStart:function(a){return this.date_part(a)},dateToStr:function(a,b){a=a.replace(/%[a-zA-Z]/g,function(a){switch(a){case "%d":return'"+dhx.math.toFixed(date.getDate())+"';case "%m":return'"+dhx.math.toFixed((date.getMonth()+1))+"';case "%j":return'"+date.getDate()+"';case "%n":return'"+(date.getMonth()+1)+"';case "%y":return'"+dhx.math.toFixed(date.getFullYear()%100)+"';case "%Y":return'"+date.getFullYear()+"';case "%D":return'"+dhx.Date.Locale.day_short[date.getDay()]+"';
|
||||
case "%l":return'"+dhx.Date.Locale.day_full[date.getDay()]+"';case "%M":return'"+dhx.Date.Locale.month_short[date.getMonth()]+"';case "%F":return'"+dhx.Date.Locale.month_full[date.getMonth()]+"';case "%h":return'"+dhx.math.toFixed((date.getHours()+11)%12+1)+"';case "%g":return'"+((date.getHours()+11)%12+1)+"';case "%G":return'"+date.getHours()+"';case "%H":return'"+dhx.math.toFixed(date.getHours())+"';case "%i":return'"+dhx.math.toFixed(date.getMinutes())+"';case "%a":return'"+(date.getHours()>11?"pm":"am")+"';
|
||||
case "%A":return'"+(date.getHours()>11?"PM":"AM")+"';case "%s":return'"+dhx.math.toFixed(date.getSeconds())+"';case "%W":return'"+dhx.math.toFixed(dhx.Date.getISOWeek(date))+"';default:return a}});b===!0&&(a=a.replace(/date\.get/g,"date.getUTC"));return new Function("date",'return "'+a+'";')},strToDate:function(a,b){for(var c="var temp=date.split(/[^0-9a-zA-Z]+/g);",d=a.match(/%[a-zA-Z]/g),e=0;e<d.length;e++)switch(d[e]){case "%j":case "%d":c+="set[2]=temp["+e+"]||1;";break;case "%n":case "%m":c+=
|
||||
"set[1]=(temp["+e+"]||1)-1;";break;case "%y":c+="set[0]=temp["+e+"]*1+(temp["+e+"]>50?1900:2000);";break;case "%g":case "%G":case "%h":case "%H":c+="set[3]=temp["+e+"]||0;";break;case "%i":c+="set[4]=temp["+e+"]||0;";break;case "%Y":c+="set[0]=temp["+e+"]||0;";break;case "%a":case "%A":c+="set[3]=set[3]%12+((temp["+e+"]||'').toLowerCase()=='am'?0:12);";break;case "%s":c+="set[5]=temp["+e+"]||0;"}var f="set[0],set[1],set[2],set[3],set[4],set[5]";b&&(f=" Date.UTC("+f+")");return new Function("date",
|
||||
"var set=[0,0,1,0,0,0]; "+c+" return new Date("+f+");")},getISOWeek:function(a){if(!a)return!1;var b=a.getDay();b===0&&(b=7);var c=new Date(a.valueOf());c.setDate(a.getDate()+(4-b));var d=c.getFullYear(),e=Math.floor((c.getTime()-(new Date(d,0,1)).getTime())/864E5),f=1+Math.floor(e/7);return f},getUTCISOWeek:function(a){return this.getISOWeek(a)},add:function(a,b,c){var d=new Date(a.valueOf());switch(c){case "day":d.setDate(d.getDate()+b);break;case "week":d.setDate(d.getDate()+7*b);break;case "month":d.setMonth(d.getMonth()+
|
||||
b);break;case "year":d.setYear(d.getFullYear()+b);break;case "hour":d.setHours(d.getHours()+b);break;case "minute":d.setMinutes(d.getMinutes()+b)}return d},datePart:function(a){var b=this.copy(a);b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0);return b},timePart:function(a){var b=this.copy(a);return(b.valueOf()/1E3-b.getTimezoneOffset()*60)%86400},copy:function(a){return new Date(a.valueOf())}};dhx.i18n.setLocale("en");dhx.format=function(a){a=a||{};this.$init(a)};
|
||||
dhx.format.prototype={$init:function(a){this.a={};this.a.groupDelimiter=a.groupDelimiter||" ";this.a.groupNumber=a.groupNumber||3;this.a.decimalPoint=a.decimalPoint||",";this.a.fractNumber=a.fractNumber||5;this.a.dateFormat=a.dateFormat||"%Y/%m/%d";this.a.stringTemplate=a.stringTemplate||"{value}";this.ff=dhx.Date.str_to_date(this.a.dateFormat);this.Qd=dhx.Date.date_to_str(this.a.dateFormat)},define:function(a,b){this.a[a]=b},format:function(a,b){b=b||this.formatAutoDefine(a);return this["format__"+
|
||||
b]?this["format__"+b](a):a},formatAutoDefine:function(a){return typeof a=="number"||a instanceof Number?"number":a instanceof Date?"date":typeof a=="string"||a instanceof String?isNaN(parseFloat(a))?"string":"number":!1},format__number:function(a){var b="";typeof a=="number"||a instanceof Number||(a=parseFloat(a));var c=a.toFixed(this.a.fractNumber).toString(),c=c.split("."),d=this.add_delimiter_to_int(c[0]),e=this.str_reverse(this.add_delimiter_to_int(this.str_reverse(c[1])));return b=d+this.a.decimalPoint+
|
||||
e},add_delimiter_to_int:function(a){for(var b=0,c="",d=a.length-1;d>=0;d--)c=a[d]+c,b++,b==this.a.groupNumber&&(c=this.a.groupDelimiter+c,b=0);return c},str_reverse:function(a){for(var b="",c=a.length-1;c>=0;c--)b+=a[c];return b},format__date:function(a){var b=this.Qd(a);return b},attachFormat:function(a,b){this["format__"+a]=b},format__string:function(a){var b=this.a.stringTemplate.replace("{value}",a);return b},format__bold:function(a){return typeof a=="string"||a instanceof String?a.bold():a}};
|
||||
dhx.i18n.setLocale();
|
||||
dhx.protoUI({name:"calendar",defaults:{date:null,startOnMonday:!0,navigation:!0,weekHeader:!1,weekNumber:!1,timeSelect:!1,skipEmptyWeeks:!0,cellHeight:36,minuteStep:15,hourStart:6,hourEnd:24,hourFormat:"%H",calendarHeader:"%F %Y",calendarDay:"%d",calendarWeekHeader:"W#",calendarWeek:"%W",width:300,height:300,selectedCss:"dhx_cal_selected_day"},skin:{monthHeaderHeight:40,weekHeaderHeight:20,timeSelectHeight:32},hourFormat_setter:dhx.Date.dateToStr,calendarHeader_setter:dhx.Date.dateToStr,calendarDay_setter:dhx.Date.dateToStr,
|
||||
calendarWeekHeader_setter:dhx.Date.dateToStr,calendarWeek_setter:dhx.Date.dateToStr,date_setter:function(a){typeof a=="string"&&(a=dhx.i18n.fullDateFormatDate(a));this.L=this.L||a;return a},$init:function(){this.fa={};this.ec=[];var a="%Y-%m-%d";this.rc=dhx.Date.dateToStr(a);this.Cd=dhx.Date.strToDate(a)},$getSize:function(){var a=this.a;if(a.cellHeight>0)a.height=this.Xd();return dhx.ui.view.prototype.$getSize.call(this)},cellHeight_setter:function(a){return a=="auto"?0:a},$setSize:function(a,b){dhx.ui.view.prototype.$setSize.call(this,
|
||||
a,b)&&this.render()},Ac:function(){var a=this.a;if(!this.L)this.L=new Date;var b=new Date(this.L);b.setDate(1);var c=b.getDay();this.ke=new Date(b);this.vd=a.startOnMonday?1:0;this.lb=(c-this.vd+7)%7;this.Nb=32-(new Date(b.getFullYear(),b.getMonth(),32)).getDate();var d=42-this.lb-this.Nb;this.df=new Date(b.setDate(this.Nb));this.G=a.skipEmptyWeeks?6-Math.floor(d/7):6;this.Ob=this.G*7-this.lb-this.Nb;this.cf=new Date(b.setDate(b.getDate()+d));this.Dc=this.skin.monthHeaderHeight+(a.weekHeader?this.skin.weekHeaderHeight:
|
||||
0)+(a.timeSelect?this.skin.timeSelectHeight:0)},Xd:function(){this.Ac();return this.Dc+this.G*this.a.cellHeight},Td:function(){this.Ac();var a=this.a;this.Da=[];this.W=[];var b=this.j;b+=1;for(var c=this.m,d=a.weekNumber?8:7,e=0;e<d;e++)this.W[e]=Math.ceil(b/(d-e)),b-=this.W[e];if(a.cellHeight<=0)for(var f=0;f<this.G;f++)this.Da[f]=Math.ceil((c-this.Dc)/(this.G-f)),c-=this.Da[f];else for(var g=0;g<this.G;g++)this.Da[g]=a.cellHeight},selectDate:function(a,b){this.define("date",a);var c=this.a;b&&this.showCalendar(c.date);
|
||||
var d=c.selectedCss;if(this.fa[this.i])dhx.html.removeCss(this.fa[this.i],d),this.i=null;var e=this.rc(c.date);if(this.fa[e])dhx.html.addCss(this.fa[e],d),this.i=e;c.timeSelect&&this.Ee(a)},Ee:function(a){var b=this.a,c=this.ec,a=a||b.date;c[0].value=Math.min(b.hourEnd,Math.max(a.getHours(),b.hourStart));c[1].value=Math.floor(a.getMinutes()/b.minuteStep)*b.minuteStep},getSelectedDate:function(){var a=this.a;return a.date?new Date(a.date):null},getVisibleDate:function(){return new Date(this.L)},setValue:function(a){this.selectDate(a,
|
||||
!0)},getValue:function(){return this.getSelectedDate()},showCalendar:function(a){typeof a=="string"&&(a=dhx.i18m.fullDateFormatDate(a));if(!a||!(a.getFullYear()==this.L.getFullYear()&&a.getMonth()==this.L.getMonth())){this.L=a||this.L;this.render();var b=this.getParent();b&&b.resize()}},refresh:function(){this.render()},render:function(){var a=this.a;if(this.isVisible(a.id)){this.callEvent("onBeforeRender",[]);this.Td();var b="<div class='dhx_mini_calendar'><div class='dhx_cal_month'>"+a.calendarHeader(this.L);
|
||||
a.navigation&&(b+=this.le());b+="</div>";a.weekHeader&&(b+="<div class='dhx_cal_header' style='height:"+this.skin.weekHeaderHeight+"px'>"+this.Xe()+"</div>");b+="<div class='dhx_cal_body'>"+this.Bd()+"</div>";a.timeSelect&&(b+="<div class='dhx_cal_time_select'>"+this.Ue()+"</div>");b+="</div></div>";this.g.innerHTML=b;if(a.timeSelect){for(var c=this.g.getElementsByTagName("select"),d=this.ec,e=0;e<c.length;e++)d[e]=c[e];d[0].onchange=function(){a.date.setHours(this.value)};d[1].onchange=function(){a.date.setMinutes(this.value)}}this.fa=
|
||||
{};for(var f=this.g.getElementsByTagName("table"),g=f[f.length-1].getElementsByTagName("div"),e=0;e<g.length;e++)this.fa[g[e].getAttribute("date")]=g[e];a.date&&this.selectDate(a.date,!1);this.callEvent("onAfterRender",[])}},Xe:function(){var a=this.a,b="",c=a.startOnMonday?1:0,d=0,e=0;if(a.weekNumber){var e=1,f=a.calendarWeekHeader();b+="<div class='dhx_cal_week_header' style='width: "+(this.W[0]-1)+"px; left: "+d+"px;' >"+f+"</div>";d+=this.W[0]}for(var g=0;g<7;g++){var h=(c+g)%7,i=dhx.Date.Locale.day_short[h],
|
||||
j="dhx_cal_day_name",k=this.W[g+e]-1;g==6&&(j+=" dhx_cal_day_name_last",k+=1);h===0&&(j+=" dhx_sunday");h==6&&(j+=" dhx_saturday");b+="<div class='"+j+"' style='width: "+k+"px; left: "+d+"px;' >"+i+"</div>";d+=this.W[g+e]}return b},Bd:function(){var a=this.a,b=0,c=dhx.Date.add(this.ke,-this.lb,"day"),c=dhx.Date.datePart(c),d=0,e="";if(a.weekNumber){var d=1,f=dhx.Date.add(c,(this.vd+1)%2,"day");e+='<table class="dhx_week_numbers" cellspacing="0" cellpadding="0" style="float: left;"><tbody>';for(var g=
|
||||
0;g<this.G;g++){var h=this.Da[g]-2,i=this.W[0]-2,j=a.calendarWeek(f),k="dhx_cal_week_num";if(!a.skipEmptyWeeks&&(g==this.G-1&&this.Ob>=7||g==this.G-2&&this.Ob==14))k="dhx_next_month",j="";g==this.G-1&&(k+=" dhx_cal_day_num_bborder",h+=1);e+="<tr><td>";e+="<div class='"+k+"' style='width:"+i+"px; height:"+h+"px; line-height:"+h+"px;' >"+j+"</div>";e+="</td></tr>";f=dhx.Date.add(f,7,"day")}e+="</tbody></table>"}var o=dhx.Date.datePart(new Date);e+='<table cellspacing="0" cellpadding="0"><tbody>';for(var m=
|
||||
this.G*7-1,g=0;g<this.G;g++){e+="<tr>";for(var l=0;l<7;l++){var n=a.calendarDay(c),p=this.rc(c),k="dhx_cal_day_num";b<this.lb&&(k="dhx_prev_month",p=n="");b>m-this.Ob&&(k="dhx_next_month",p=n="");h=this.Da[g]-2;i=this.W[l+d]-2;l==6&&(k+=" dhx_cal_day_num_rborder",i+=1);g==this.G-1&&(k+=" dhx_cal_day_num_bborder",h+=1);e+="<td>";o.valueOf()==c.valueOf()&&(k+=" dhx_cal_current_day");e+="<div class='"+k+"' style='width:"+i+"px; height:"+h+"px; line-height:"+h+"px;' date='"+p+"'>"+n+"</div>";e+="</td>";
|
||||
c=dhx.Date.add(c,1,"day");b++}e+="</tr>"}e+="</tbody></table>";return e},Ue:function(){for(var a=this.a,b="<select class='dhx_hour_select' onclick=''>",c=a.hourStart,d=a.hourEnd,e=dhx.Date.datePart(new Date),f=c;f<d;f++)e.setHours(f),b+="<option value='"+f+"'>"+a.hourFormat(e)+"</option>";b+="</select>";b+="<select class='dhx_minute_select' onclick=''>";for(var g=0;g<60;g+=a.minuteStep)b+="<option value='"+g+"'>"+dhx.math.toFixed(g)+"</option>";b+="</select>";return b},le:function(){var a="<div class='dhx_cal_arrow dhx_cal_",
|
||||
b="_button'><div></div></div>";return a+"prev"+b+a+"next"+b},on_click:{dhx_cal_arrow:function(a,b,c){var d=c.className.match(/prev/i)?-1:1,e=new Date(this.L),f=new Date(e);f.setDate(1);f=dhx.Date.add(f,d,"month");this.callEvent("onBeforeMonthChange",[e,f])&&(this.showCalendar(f),this.selectDate(this.a.date,!1),this.callEvent("onAfterMonthChange",[f,e]))},dhx_cal_day_num:function(a,b,c){var d=c.getAttribute("date"),e=this.Cd(d);if(this.a.timeSelect){var f=this.ec;e.setMinutes(f[0].value*60+f[1].value*
|
||||
1)}this.selectDate(e);this.callEvent("onDateSelect",[e]);this.callEvent("onChange",[e])}}},dhx.MouseEvents,dhx.Settings,dhx.EventSystem,dhx.Movable,dhx.ui.view);dhx.Modality={modal_setter:function(a){if(a){if(!this.qa)this.qa=dhx.html.create("div",{"class":a=="rich"?"dhx_modal_rich":"dhx_modal"}),this.qa.style.zIndex=dhx.ui.zIndex(),this.b.style.zIndex=dhx.ui.zIndex(),document.body.appendChild(this.qa)}else this.qa&&dhx.html.remove(this.qa),this.qa=null;return a}};
|
||||
dhx.protoUI({name:"window",$init:function(a){this.b.innerHTML="<div class='dhx_win_content'><div class='dhx_win_head'></div><div class='dhx_win_body'></div></div>";this.g=this.b.firstChild;this.eb=this.g.childNodes[0];this.pc=this.g.childNodes[1];this.b.className+=" dhx_window";this.R=this.h=null;this.a.k={top:!1,left:!1,right:!1,bottom:!1};if(!a.id)a.id=dhx.uid()},Zc:function(){this.h={destructor:function(){}}},ac:function(a){this.h.destructor();this.h=a;this.h.D=this;this.pc.appendChild(this.h.b);
|
||||
this.resize()},show:function(a,b,c){this.a.hidden=!1;this.b.style.zIndex=dhx.ui.zIndex();this.a.modal&&this.modal_setter(!0);var d,e,f;if(a){typeof a=="object"&&!a.tagName?(d={x:a.clientX-this.$[0]/2,y:a.clientY},e=document.body.offsetWidth,f=1):a=dhx.toNode(a);var g=document.body.offsetWidth,h=document.body.offsetHeight;e=e||a.offsetWidth;f=f||a.offsetHeight;var i=this.$;d=d||dhx.html.offset(a);var j=6,k=6,o=6,c="top",m=0,l=0,n=0,p=0;b=="right"?(p=d.x+j+e,k=-f,c="left",m=Math.round(d.y+f/2),l=p-
|
||||
o):b=="left"?(p=d.x-j-i[0]-1,k=-f,c="right",m=Math.round(d.y+f/2),l=p+i[0]+1):(p=g-d.x>i[0]?d.x:g-j-i[0],l=Math.round(d.x+e/2),l>p+i[0]&&(l=p+i[0]/2));h-f-d.y-k>i[1]?(n=f+d.y+k,m||(c="top",m=n-o)):(n=d.y-k-i[1],n<0?(n=0,c=!1):m||(c="bottom",n--,m=n+i[1]+1));this.setPosition(p,n);c&&this.cd&&this.cd(c,l,m)}this.Le=new Date;this.b.style.display="block";if(this.la){for(var q=0;q<this.la.length;q++)dhx.ui.get(this.la[q]).render();this.la=[];this.Jb={}}this.callEvent("onShow",[])},hidden_setter:function(a){a?
|
||||
this.hide():this.show();return!!a},hide:function(){!this.a.hidden&&!(new Date-this.Le<100)&&(this.a.modal&&this.modal_setter(!1),this.a.position=="top"?dhx.animate(this.b,{type:"slide",x:0,y:0,duration:300,callback:this.Ec,master:this}):this.Ec())},Ec:function(){this.b.style.display="none";this.a.hidden=!0;this.callEvent("onHide",[])},close:function(){this.define("modal",!1);dhx.html.remove(this.b);this.destructor()},body_setter:function(a){typeof a!="object"&&(a={template:a});this.h=dhx.ui.Oa(a);
|
||||
this.h.D=this;this.pc.appendChild(this.h.b);return a},head_setter:function(a){if(a===!1)return a;typeof a!="object"&&(a={template:a,css:"dhx_alert_template"});this.R=dhx.ui.Oa(a);this.R.D=this;this.eb.appendChild(this.R.b);return a},getBody:function(){return this.h},getHead:function(){return this.R},resize:function(){var a=this.$getSize();this.$setSize(a[1]||this.a.width,a[3]||this.a.height);this.cc(this.a.left,this.a.top)},cc:function(a,b){if(this.a.position){var c=Math.round((document.body.offsetWidth-
|
||||
this.a.width)/2),d=Math.round((document.body.offsetHeight-this.a.height)/2);this.a.position=="top"&&(d=dhx.animate.isSupported()?-1*this.a.height:10);this.setPosition(c,d);this.a.position=="top"&&dhx.animate(this.b,{type:"slide",x:0,y:this.a.height,duration:300})}else this.setPosition(a,b)},setPosition:function(a,b){this.b.style.top=b+"px";this.b.style.left=a+"px";this.a.left=a;this.a.top=b},$getSize:function(){var a=this.h.$getSize();if(this.R){var b=this.R.$getSize();if(b[3])this.a.headHeight=b[3]}if(a[3])a[3]+=
|
||||
this.a.head!==!1?this.a.headHeight:0,this.a.height=a[3];if(a[1])this.a.width=a[1];if(a[0]||a[2])this.a.gravity=Math.max(a[0],a[2]);return dhx.ui.view.prototype.$getSize.call(this)},$setSize:function(a,b){if(dhx.ui.view.prototype.$setSize.call(this,a,b))a=this.j,b=this.m,this.a.head===!1?(this.eb.style.display="none",this.h.$setSize(a,b)):(this.R.$setSize(a,this.a.headHeight),this.h.$setSize(a,b-this.a.headHeight))},defaults:{headHeight:43,width:300,height:200,top:100,left:100,body:"",head:""}},dhx.ui.view,
|
||||
dhx.Movable,dhx.Modality,dhx.EventSystem);
|
||||
dhx.protoUI({name:"popup",$init:function(){this.a.head=!1;dhx.event(this.g,"click",dhx.bind(this.Id,this));dhx.attachEvent("onClick",dhx.bind(this.Ha,this));this.attachEvent("onHide",this.Fc)},Id:function(){this.Me=new Date},Ha:function(){new Date-(this.Me||0)>250&&this.hide()},$getSize:function(){var a=this.h.$getSize();if(a[3])this.a.height=a[3]+this.a.padding*2;if(a[1])this.a.width=a[1]+this.a.padding*2;if(a[0]||a[2])this.a.gravity=Math.max(a[0],a[2]);return dhx.ui.view.prototype.$getSize.call(this)},
|
||||
$setSize:function(a,b){if(dhx.ui.view.prototype.$setSize.call(this,a,b))a=this.j-this.a.padding*2,b=this.m-this.a.padding*2,this.g.style.padding=this.a.padding+"px",this.eb.style.display="none",this.h.$setSize(a,b)},body_setter:function(a){a=dhx.ui.window.prototype.body_setter.call(this,a);this.h.a.k={top:!1,left:!1,right:!1,bottom:!1};return a},defaults:{padding:8},head_setter:null,cd:function(a,b,c){this.Fc();document.body.appendChild(this.Ka=dhx.html.create("DIV",{"class":"dhx_point_"+a},""));
|
||||
this.Ka.style.zIndex=dhx.ui.zIndex();this.Ka.style.top=c+"px";this.Ka.style.left=b+"px"},Fc:function(){this.Ka=dhx.html.remove(this.Ka)}},dhx.ui.window);
|
||||
dhx.protoUI({name:"alert",defaults:{position:"center",head:{template:"Info",css:"dhx_alert_template"},height:170,modal:!0,callback:null,body:{type:"clean",rows:[{template:"<div class='dhx_alert_text'>#text#</div>",data:{text:"You have forgot to define the text :) "}},{view:"button",height:60,id:"dhx_alert_ok",type:"big",label:"Ok",click:function(){this.getParent().getParent().Bb(!0)}}]}},$init:function(){(!this.b.parentNode||!this.b.parentNode.tagName)&&document.body.appendChild(this.b);this.$ready.push(this.resize)},
|
||||
Yc:function(a){typeof a=="string"&&(a={title:this.defaults.head.template,message:a});dhx.extend(a,this.defaults);delete a.head;delete a.body;this.Rb(a,{});this.resize();this.show()},title_setter:function(a){this.R.define("template",a);this.R.render()},message_setter:function(a){var b=this.h.c[0];b.data={text:a};b.render()},labelOk_setter:function(a){var b=this.h.c[1];b.config.label=a;b.render()},labelCancel_setter:function(a){var b=this.h.c[2];b.config.label=a;b.render()},Bb:function(a){this.hide();
|
||||
this.a.callback&&dhx.toFunctor(this.a.callback).call(this,a,this.a.details)}},dhx.ui.window);dhx.alert=dhx.single(dhx.ui.alert);
|
||||
dhx.protoUI({name:"confirm",defaults:{height:210,body:{type:"clean",rows:[{id:"dhx_confirm_message",template:"<div class='dhx_alert_text'>#text#</div>",data:{text:"You have forgot to define the text :) "}},{height:53,view:"button",type:"big",id:"dhx_confirm_ok",label:"Ok",click:function(){this.getParent().getParent().Bb(!0)}},{height:55,view:"button",type:"biground",id:"dhx_confirm_cancel",label:"Cancel",click:function(){this.getParent().getParent().Bb(!1)}}]}}},dhx.ui.alert);dhx.confirm=dhx.single(dhx.ui.confirm);
|
||||
dhx.dp=function(a){if(typeof a=="object"&&a.a)a=a.a.id;if(dhx.dp.Tb[a])return dhx.dp.Tb[a];if(typeof a=="string"||typeof a=="number")a={master:dhx.ui.get(a)};var b=new dhx.DataProcessor(a);return dhx.dp.Tb[b.a.master.a.id]=b};dhx.dp.Tb={};
|
||||
dhx.DataProcessor=dhx.proto({defaults:{autoupdate:!0,mode:"post"},$init:function(){this.V=[];this.bf=[];this.X=null;this.na=!1;this.name="DataProcessor";this.$ready.push(this.zb)},master_setter:function(a){var b=a;if(a.name!="DataStore")b=a.data;this.a.store=b;return a},zb:function(){this.a.store.attachEvent("onStoreUpdated",dhx.bind(this.Sc,this))},ignore:function(a,b){var c=this.na;this.na=!0;a.call(b||this);this.na=c},off:function(){this.na=!0},on:function(){this.na=!1},Kd:function(a){var b={},
|
||||
c;for(c in a)c.indexOf("$")!==0&&(b[c]=a[c]);return b},save:function(a,b){b=b||"update";this.Sc(a,this.a.store.item(a),b)},Sc:function(a,b,c){if(this.na===!0||!c)return!0;var d={id:a,data:this.Kd(b)};switch(c){case "update":d.operation="update";break;case "add":d.operation="insert";break;case "delete":d.operation="delete";break;default:return!0}if(d.operation!="delete"&&!this.validate(d.data))return!1;this.Gd(d)&&this.V.push(d);this.a.autoupdate&&this.send();return!0},Gd:function(a){for(var b=0;b<
|
||||
this.V.length;b++){var c=this.V[b];if(c.id==a.id){if(a.operation=="delete")c.operation=="insert"?this.V.splice(b,1):c.operation="delete";c.data=a.data;return!1}}return!0},send:function(){this.Ge()},Ge:function(){if(this.a.url){for(var a=this.V,b=[],c=0;c<a.length;c++){var d=a[c].id,e=a[c].operation;if(this.a.store.exists(d))a[c].data=this.a.store.item(d);this.callEvent("onBefore"+e,[d,a[c].data])&&b.push(a[c])}b.length&&this.callEvent("onBeforeDataSend",[b])&&this.Fe(this.a.url,this.We(b),this.a.mode)}},
|
||||
We:function(a){for(var b={},c=[],d=0;d<a.length;d++){var e=a[d];c.push(e.id);b[e.id+"_!nativeeditor_status"]=e.operation;for(var f in e.data)f.indexOf("$")!==0&&(b[e.id+"_"+f]=e.data[f])}b.ids=c.join(",");return b},Fe:function(a,b,c){if(typeof a=="function")return a(b);a+=a.indexOf("?")==-1?"?":"&";a+="editing=true";dhx.ajax()[c](a,b,dhx.bind(this.ye,this))},ye:function(a,b,c){this.callEvent("onBeforeSync",[f,a,b,c]);for(var d=dhx.DataDriver.xml,b=d.toObject(a,d),e=d.xpath(b,"//action"),f=[],g=0;g<
|
||||
e.length;g++){var h=d.tagToObject(e[g]);f.push(h);for(var i=-1,j=0;j<this.V.length;){this.V[j].id==h.sid&&(i=j);break}if(!(h.type=="error"||h.type=="invalid")||this.callEvent("onDBError",[h,this.V[i]]))i>=0&&this.V.splice(i,1),h.tid!=h.sid&&this.a.store.changeId(h.sid,h.tid),this.callEvent("onAfter"+h.type,[h])}this.callEvent("onAfterSync",[f,a,b,c])},escape:function(a){return this.a.escape?this.a.escape(a):encodeURIComponent(a)}},dhx.Settings,dhx.EventSystem,dhx.ValidateData);
|
||||
(function(){var a=dhx.Touch={config:{longTouchDelay:1E3,scrollDelay:150,gravity:500,deltaStep:30,speed:"0ms",finish:1500},disable:function(){a.Fb=!0},enable:function(){a.Fb=!1},$init:function(){dhx.env.touch?(dhx.event(document.body,"touchstart",a.nd),dhx.event(document.body,"touchmove",a.gc),dhx.event(document.body,"touchend",a.md)):(a.bb=a.Wd,dhx.event(document.body,"mousedown",a.nd),dhx.event(document.body,"mousemove",a.gc),dhx.event(document.body,"mouseup",a.md),document.body.style.overflowX=
|
||||
document.body.style.overflowY="hidden");dhx.event(document.body,"dragstart",function(a){return dhx.html.preventEvent(a)});dhx.event(document.body,"touchstart",function(b){if(!a.Fb&&dhx.env.isSafari)return b.srcElement.tagName=="SELECT"?!0:dhx.html.preventEvent(b)});a.Ca()},Ca:function(){a.A=a.w=a.ca=null;a.H=a.v=a.n=null;a.I={wb:0,xb:0,Na:0};if(a.Xa)dhx.html.removeCss(a.Xa,"dhx_touch"),a.Xa=null;window.clearTimeout(a.Kc);a.ud=!0;a.Sa=!0;a.Ta=!0;a.ic||a.ua()},md:function(b){if(a.A){if(a.H){var c=a.Hb(a.v),
|
||||
d=c.e,e=c.f,f=a.config.finish,g=a.Bc(b,!0);if(g.Na){var h=d+a.config.gravity*g.wb/g.Na,i=e+a.config.gravity*g.xb/g.Na,j=a.q[0]?a.Wa(h,!1,!1,a.n.dx,a.n.px):d,k=a.q[1]?a.Wa(i,!1,!1,a.n.dy,a.n.py):e,o=Math.max(Math.abs(j-d),Math.abs(k-e));o<150&&(f=f*o/150);if(j!=d||k!=e)f=Math.round(f*Math.max((j-d)/(h-d),(k-e)/(i-e)));var m={e:j,f:k},l=dhx.ui.get(a.v);l&&l.callEvent&&l.callEvent("onAfterScroll",[m]);f=Math.max(100,f);d!=m.e||e!=m.f?(a.wa(a.v,m.e,m.f,f+"ms"),a.dd(m.e,m.f,f+"ms")):a.ua()}else a.ua()}else if(a.Ta&&
|
||||
!a.Sa)a.ya("onSwipeX");else if(a.Sa&&!a.Ta)a.ya("onSwipeY");else if(dhx.env.isSafari){var n=a.A.target;dhx.delay(function(){var a=document.createEvent("MouseEvents");a.initEvent("click",!0,!0);n.dispatchEvent(a)})}a.ya("onTouchEnd");a.Ca()}},gc:function(b){if(a.A){var c=a.Bc(b);a.ya("onTouchMove");if(a.H)a.ed(c);else if(a.Sa=a.lc(c.Ye,"x",a.Sa),a.Ta=a.lc(c.Ze,"y",a.Ta),a.H){var d=a.Cc("onBeforeScroll");if(d){var e={};d.callEvent("onBeforeScroll",[e]);if(e.update)a.config.speed=e.speed,a.config.scale=
|
||||
e.scale}a.ce(c)}return dhx.html.preventEvent(b)}},ed:function(){if(a.v){var b=a.Hb(a.v),c=b.e,d=b.f,e=a.ca||a.A;if(a.q[0])b.e=a.Wa(b.e-e.x+a.w.x,!0,b.e,a.n.dx,a.n.px);if(a.q[1])b.f=a.Wa(b.f-e.y+a.w.y,!0,b.f,a.n.dy,a.n.py);a.wa(a.v,b.e,b.f,"0ms");a.dd(b.e,b.f,"0ms")}},dd:function(b,c,d){var e=a.n.px/a.n.dx*-b,f=a.n.py/a.n.dy*-c;a.q[0]&&a.wa(a.q[0],e,0,d);a.q[1]&&a.wa(a.q[1],0,f,d)},wa:function(b,c,d,e){a.ic=!0;b.style[dhx.env.transformPrefix+"Transform"]=dhx.env.translate+"("+Math.round(c)+"px, "+
|
||||
Math.round(d)+"px"+(dhx.env.translate=="translate3d"?", 0":"")+")";b.style[dhx.env.transformPrefix+"TransitionDuration"]=e},Hb:function(a){var c=window.getComputedStyle(a)[dhx.env.transformPrefix+"Transform"];if(c=="none")return{e:0,f:0};else{if(window.WebKitCSSMatrix)return new WebKitCSSMatrix(c);for(var d=c.replace(/(matrix\()(.*)(\))/gi,"$2"),d=d.replace(/\s/gi,""),d=d.split(","),e={},f="a,b,c,d,e,f".split(","),g=0;g<f.length;g++)e[f[g]]=parseInt(d[g],10);return e}},Wa:function(a,c,d,e,f){if(a===
|
||||
d)return a;var g=Math.abs(a-d),h=g/(a-d);if(a>0)return c?d+h*Math.sqrt(g):0;var i=e-f;return i+a<0?c?d-Math.sqrt(-(a-d)):-i:a},ce:function(){a.H.indexOf("x")!=-1&&(a.q[0]=a.vc("x",a.n.dx,a.n.px,"width"));a.H.indexOf("y")!=-1&&(a.q[1]=a.vc("y",a.n.dy,a.n.py,"height"));if(!a.v.scroll_enabled){a.v.scroll_enabled=!0;a.v.parentNode.style.position="relative";var b=dhx.env.transformCSSPrefix;a.v.style.cssText+=b+"transition: "+b+"transform; "+b+"user-select:none; "+b+"transform-style:flat;";a.v.addEventListener(dhx.env.transitionEnd,
|
||||
a.ua,!1)}window.setTimeout(a.ed,1)},vc:function(b,c,d,e){if(c-d<2)return a.H="";var f=dhx.html.create("DIV",{"class":"dhx_scroll_"+b},"");f.style[e]=d*d/c-7+"px";a.v.parentNode.appendChild(f);return f},lc:function(b,c,d){if(b>a.config.deltaStep){if(a.ud&&(a.he(c),(a.H||"").indexOf(c)==-1))a.H="";return!1}return d},ua:function(){if(!a.H)dhx.html.remove(a.q),a.q=[null,null];a.ic=!1},he:function(b){window.clearTimeout(a.Kc);a.ud=!1;a.Jc(b)},nd:function(b){if(!a.Fb){a.A=a.bb(b);a.ya("onTouchStart");a.q[0]||
|
||||
a.q[1]?a.Re(b,a.q[0]?"x":"y"):a.Kc=window.setTimeout(a.ie,a.config.longTouchDelay);var c=dhx.ui.get(b);if(c&&c.touchable&&(!b.target.className||b.target.className.indexOf("dhx_view")!==0))a.Xa=c.getNode(b),dhx.html.addCss(a.Xa,"dhx_touch")}},ie:function(){a.ya("onLongTouch");dhx.callEvent("onClick",[a.A]);a.Ca()},Re:function(b,c){a.Jc(c);var d=a.q[0]||a.q[1];if(d&&(!a.v||d.parentNode!=a.v.parentNode))a.Ca(),a.ua(),a.A=a.bb(b);a.gc(b)},Bc:function(b){a.ca=a.w;a.w=a.bb(b);a.I.Ye=Math.abs(a.A.x-a.w.x);
|
||||
a.I.Ze=Math.abs(a.A.y-a.w.y);if(a.ca)a.w.time-a.ca.time<a.config.scrollDelay?(a.I.wb=a.I.wb/1.3+a.w.x-a.ca.x,a.I.xb=a.I.xb/1.3+a.w.y-a.ca.y):a.I.xb=a.I.wb=0,a.I.Na=a.I.Na/1.3+(a.w.time-a.ca.time);return a.I},Jc:function(b){var c=a.A.target;if(dhx.env.touch||dhx.env.transition||dhx.env.transform)for(;c&&c.tagName!="BODY";){if(c.getAttribute){var d=c.getAttribute("touch_scroll");if(d&&(!b||d.indexOf(b)!=-1)){a.H=d;a.v=c;a.n={dx:c.offsetWidth,dy:c.offsetHeight,px:c.parentNode.offsetWidth,py:c.parentNode.offsetHeight};
|
||||
break}}c=c.parentNode}},ya:function(b){dhx.callEvent(b,[a.A,a.w]);var c=a.Cc(b);c&&c.callEvent(b,[a.A,a.w])},Cc:function(b){var c=dhx.ui.get(a.A);if(!c)return null;for(;c;){if(c.hasEvent&&c.hasEvent(b))return c;c=c.getParent()}return null},bb:function(b){if(!b.touches[0]){var c=a.w;c.time=new Date;return c}return{target:b.target,x:b.touches[0].pageX,y:b.touches[0].pageY,time:new Date}},Wd:function(a){return{target:a.target,x:a.pageX,y:a.pageY,time:new Date}}};dhx.TouchEvents={$init:function(){this.attachEvent("onSwipeX",
|
||||
this.Se);this.attachEvent("onBeforeSelect",this.unSwipe);this.attachEvent("onAfterDelete",this.unSwipe)},Se:function(a){var c=this.locate(a);c&&c!=this.ea&&(this.unSwipe(),this.swipe(c))},swipe:function(a){this.ea=a;this.item(this.ea).$template="Swipe";this.refresh(this.ea)},unSwipe:function(){if(this.ea){var a=this.item(this.ea);if(a)a.$template="",this.refresh(this.ea);this.ea=null}}};dhx.ready(function(){a.$init()})})();
|
||||
dhx.protoUI({name:"googlemap",$init:function(a){if(!a.id)a.id=dhx.uid();this.b.innerHTML="<div class='dhx_map_content' style='width:100%;height:100%'></div>";this.g=this.b.firstChild;this.map=null;this.$ready.push(this.render)},render:function(){var a=this.a,b={zoom:a.zoom,center:a.center,mapTypeId:a.mapType};this.map=new google.maps.Map(this.g,b)},center_setter:function(a){typeof a!="object"&&(a={});this.Ia(a,{x:48.724,y:8.215});a=new google.maps.LatLng(a.x,a.y);this.map&&this.map.setCenter(a);return a},
|
||||
mapType_setter:function(a){a=google.maps.MapTypeId[a];this.map&&this.map.setMapTypeId(a);return a},zoom_setter:function(a){this.map&&this.map.setZoom(a);return a},defaults:{zoom:5,center:{},mapType:"ROADMAP"},$setSize:function(){dhx.ui.view.prototype.$setSize.apply(this,arguments);google.maps.event.trigger(this.map,"resize")}},dhx.ui.view);if(!window.scheduler)window.scheduler={config:{},templates:{},xy:{},locale:{}};if(!scheduler.locale)scheduler.locale={};
|
||||
scheduler.locale.labels={list_tab:"List",day_tab:"Day",month_tab:"Month",icon_today:"Today",icon_save:"Save",icon_delete:"Delete event",icon_cancel:"Cancel",icon_edit:"Edit",icon_back:"Back",icon_close:"Close form",icon_yes:"Yes",icon_no:"No",confirm_closing:"Your changes will be lost, are your sure ?",confirm_deleting:"Event will be deleted permanently, are you sure?",label_event:"Event",label_start:"Start",label_end:"End",label_details:"Notes",label_from:"from",label_to:"to"};
|
||||
scheduler.config={init_date:new Date,form_date:"%d-%m-%Y %H:%i",xml_date:"%Y-%m-%d %H:%i",item_date:"%d.%m.%Y",header_date:"%d.%m.%Y",hour_date:"%H:%i",scale_hour:"%H",calendar_date:"%F %Y"};scheduler.config.form_rules={end_date:function(a,b){return b.start_date.valueOf()<a.valueOf()}};scheduler.xy={confirm_height:231,confirm_width:250,scale_width:45,scale_height:15,list_tab:54,day_tab:54,month_tab:68,icon_today:72,icon_save:100,icon_cancel:100,icon_edit:100,icon_back:100,list_height:42,month_list_height:42};
|
||||
scheduler.templates={selected_event:function(a){var b="";if(!a.start_date)return b;b+="<div class='selected_event'>";b+="<div class='event_title'>"+a.text+"</div>";if(dhx.Date.datePart(a.start_date).valueOf()==dhx.Date.datePart(a.end_date).valueOf()){var c=dhx.i18n.dateFormatStr(a.start_date),d=dhx.i18n.timeFormatStr(a.start_date),e=dhx.i18n.timeFormatStr(a.end_date);b+="<div class='event_text'>"+c+"</div>";b+="<div class='event_text'>"+scheduler.locale.labels.label_from+" "+d+" "+scheduler.locale.labels.label_to+
|
||||
" "+e+"</div>"}else{var f=dhx.i18n.longDateFormatStr(a.start_date),g=dhx.i18n.longDateFormatStr(a.end_date),d=dhx.i18n.timeFormatStr(a.start_date),e=dhx.i18n.timeFormatStr(a.end_date);b+="<div class='event_text'>"+scheduler.locale.labels.label_from+" "+d+" "+f+"</div>";b+="<div class='event_text'>"+scheduler.locale.labels.label_to+" "+e+" "+g+"</div>"}a.details&&a.details!==""&&(b+="<div class='event_title'>"+scheduler.locale.labels.label_details+"</div>",b+="<div class='event_text'>"+a.details+"</div>");
|
||||
b+="</div>";return b},calendar_event:function(a){return a+"<div class='day_with_events'></div>"},event_date:function(a){return dhx.i18n.dateFormatStr(a)},event_long_date:function(a){return dhx.i18n.longDateFormatStr(a)},event_time:function(a){return dhx.i18n.timeFormatStr(a)},event_color:function(a){return a.color?"background-color:"+a.color:""},event_marker:function(a,b){return"<div class='dhx_event_marker' style='"+b.color(a)+"'></div>"},event_title:function(a,b){return"<div class='dhx_day_title'>"+
|
||||
b.dateStart(a.start_date)+"</div><div style='margin:10px'><div class='dhx_event_time'>"+b.timeStart(a.start_date)+"</div>"+b.marker(a,b)+"<div class='dhx_event_text'>"+a.text+"</div></div>"},month_event_title:function(a,b){return b.marker(a,b)+"<div class='dhx_event_time'>"+b.timeStart(a.start_date)+"</div><div class='dhx_event_text'>"+a.text+"</div>"},day_event:function(a){return a.text}};scheduler.config.views=[];
|
||||
dhx.ready(function(){if(scheduler.locale&&scheduler.locale.date)dhx.Date.Locale=scheduler.locale.date;if(!scheduler.config.form)scheduler.config.form=[{view:"text",label:scheduler.locale.labels.label_event,name:"text"},{view:"datepicker",label:scheduler.locale.labels.label_start,name:"start_date",timeSelect:1,dateFormat:scheduler.config.form_date},{view:"datepicker",label:scheduler.locale.labels.label_end,name:"end_date",timeSelect:1,dateFormat:scheduler.config.form_date},{view:"textarea",label:scheduler.locale.labels.label_details,
|
||||
name:"details",width:300,height:150},{view:"button",label:scheduler.locale.labels.icon_delete,id:"delete",type:"form",css:"delete"}];if(!scheduler.config.bottom_toolbar)scheduler.config.bottom_toolbar=[{view:"button",id:"today",label:scheduler.locale.labels.icon_today,inputWidth:scheduler.xy.icon_today,align:"left",width:scheduler.xy.icon_today+6},{view:"segmented",id:"buttons",selected:"list",align:"center",multiview:!0,options:[{value:"list",label:scheduler.locale.labels.list_tab,width:scheduler.xy.list_tab},
|
||||
{value:"day",label:scheduler.locale.labels.day_tab,width:scheduler.xy.day_tab},{value:"month",label:scheduler.locale.labels.month_tab,width:scheduler.xy.month_tab}]},{view:"button",css:"add",id:"add",align:"right",label:"",inputWidth:42,width:50},{view:"label",label:"",inputWidth:42,width:50,batch:"readonly"}];if(!scheduler.config.day_toolbar)scheduler.config.day_toolbar=[{view:"label",id:"prev",align:"left",label:"<div class='dhx_cal_prev_button'><div></div></div>"},{view:"label",id:"date",align:"center",
|
||||
width:200},{view:"label",id:"next",align:"right",label:"<div class='dhx_cal_next_button'><div></div></div>"}];if(!scheduler.config.selected_toolbar)scheduler.config.selected_toolbar=[{view:"button",inputWidth:scheduler.xy.icon_back,type:"prev",id:"back",align:"left",label:scheduler.locale.labels.icon_back},{view:"button",inputWidth:scheduler.xy.icon_edit,id:"edit",align:"right",label:scheduler.locale.labels.icon_edit}];if(!scheduler.config.form_toolbar)scheduler.config.form_toolbar=[{view:"button",
|
||||
inputWidth:scheduler.xy.icon_cancel,id:"cancel",css:"cancel",align:"left",label:scheduler.locale.labels.icon_cancel},{view:"button",inputWidth:scheduler.xy.icon_save,id:"save",align:"right",label:scheduler.locale.labels.icon_save}];scheduler.types={event_list:{name:"EventsList",css:"events",cssNoEvents:"no_events",padding:0,height:scheduler.xy.list_height,width:"auto",dateStart:scheduler.templates.event_date,timeStart:scheduler.templates.event_time,color:scheduler.templates.event_color,marker:scheduler.templates.event_marker,
|
||||
template:scheduler.templates.event_title},day_event_list:{name:"DayEventsList",css:"day_events",cssNoEvents:"no_events",padding:0,height:scheduler.xy.month_list_height,width:"auto",timeStart:scheduler.templates.event_time,color:scheduler.templates.event_color,marker:scheduler.templates.event_marker,template:scheduler.templates.month_event_title}};dhx.Type(dhx.ui.list,scheduler.types.event_list);dhx.Type(dhx.ui.list,scheduler.types.day_event_list);dhx.DataDriver.scheduler={records:"/*/event"};dhx.extend(dhx.DataDriver.scheduler,
|
||||
dhx.DataDriver.xml);var a=[{id:"list",view:"list",type:"EventsList",startDate:new Date},{id:"day",rows:[{id:"dayBar",view:"toolbar",css:"dhx_topbar",elements:scheduler.config.day_toolbar},{id:"dayList",view:"dayevents"}]},{id:"month",rows:[{id:"calendar",view:"calendar",dayWithEvents:scheduler.templates.calendar_event,calendarHeader:scheduler.config.calendar_date},{id:"calendarDayEvents",view:"list",type:"DayEventsList"}]},{id:"event",animate:{type:"slide",subtype:"in",direction:"top"},rows:[{id:"eventBar",
|
||||
view:"toolbar",type:"TopBar",css:"single_event",elements:scheduler.config.selected_toolbar},{id:"eventTemplate",view:"template",template:scheduler.templates.selected_event}]},{id:"form",rows:[{id:"editBar",view:"toolbar",type:"TopBar",elements:scheduler.config.form_toolbar},{id:"editForm",view:"form",elements:scheduler.config.form,rules:scheduler.config.form_rules}]}].concat(scheduler.config.views);dhx.protoUI({name:"scheduler",defaults:{rows:[{view:"multiview",id:"views",cells:a},{view:"toolbar",
|
||||
id:"bottomBar",type:"SchedulerBar",visibleBatch:"default",elements:scheduler.config.bottom_toolbar}],color:"#color#",textColor:"#textColor#"},$init:function(){this.name="Scheduler";this.b.className+=" dhx_scheduler";dhx.i18n.dateFormat=scheduler.config.item_date;dhx.i18n.timeFormat=scheduler.config.hour_date;dhx.i18n.fullDateFormat=scheduler.config.xml_date;dhx.i18n.headerFormatStr=dhx.Date.dateToStr(scheduler.config.header_date);dhx.i18n.setLocale();this.data.provideApi(this);this.data.extraParser=
|
||||
dhx.bind(function(a){a.start_date=dhx.i18n.fullDateFormatDate(a.start_date);a.end_date=dhx.i18n.fullDateFormatDate(a.end_date)},this);this.$ready.push(this.$d);this.data.attachEvent("onStoreUpdated",dhx.bind(this.Oe,this))},$d:function(){this.ae();this.de();this.coreData=new dhx.DataValue;this.coreData.setValue(scheduler.config.init_date);this.$$("dayList").define("date",this.coreData);this.selectedEvent=new dhx.DataRecord;this.config.readonly?this.define("readonly",this.config.readonly):scheduler.config.readonly&&
|
||||
this.define("readonly",!0);if(this.config.save){var a=new dhx.DataProcessor({master:this,url:this.config.save});a.attachEvent("onBeforeDataSend",this.re)}this.$$("date")&&this.$$("date").bind(this.coreData,null,dhx.i18n.headerFormatStr);this.$$("list").sync(this);this.$$("list").bind(this.coreData,function(a,b){return b<a.end_date});this.$$("dayList").sync(this,!0);this.$$("dayList").bind(this.coreData,function(a,b){var e=dhx.Date.datePart(b);return e<a.end_date&&dhx.Date.add(e,1,"day")>a.start_date});
|
||||
this.$$("calendar").bind(this.coreData);this.$$("calendarDayEvents").sync(this,!0);this.$$("calendarDayEvents").bind(this.coreData,function(a,b){var e=dhx.Date.datePart(b);return e<a.end_date&&dhx.Date.add(e,1,"day")>a.start_date});this.$$("eventTemplate").bind(this);this.$$("editForm").bind(this);this.$$("list").attachEvent("onItemClick",dhx.bind(this.Qb,this));this.$$("dayList").attachEvent("onItemClick",dhx.bind(this.Qb,this));this.$$("calendarDayEvents").attachEvent("onItemClick",dhx.bind(this.Qb,
|
||||
this))},Qb:function(a){this.setCursor(a);this.$$("event").show()},Oe:function(){this.data.blockEvent();this.data.sort(function(a,b){return a.start_date<b.start_date?1:-1});this.data.unblockEvent();this.Gb={};for(var a=this.data.getRange(),c=0;c<a.length;c++)this.He(a[c])},He:function(a){var c=dhx.Date.datePart(a.start_date),d=dhx.Date.datePart(a.end_date);for(a.end_date.valueOf()!=d.valueOf()&&(d=dhx.Date.add(d,1,"day"));c<d;)this.Gb[c.valueOf()]=!0,c=dhx.Date.add(c,1,"day")},de:function(){this.$$("calendar").attachEvent("onDateSelect",
|
||||
dhx.bind(function(a){this.setDate(a)},this));this.$$("calendar").attachEvent("onAfterMonthChange",dhx.bind(function(a){var b=new Date;a.getMonth()===b.getMonth()&&a.getYear()===b.getYear()?a=b:a.setDate(1);this.setDate(a)},this));var a=this.$$("calendar").config.calendarDay;this.$$("calendar").config.calendarDay=dhx.bind(function(c){var d=a(c);return this.Gb&&this.Gb[c.valueOf()]?this.$$("calendar").config.dayWithEvents(d):d},this)},setDate:function(a,c,d){a||(a=this.coreData.getValue());c&&(a=dhx.Date.add(a,
|
||||
c,d));this.coreData.setValue(a)},ae:function(){this.attachEvent("onItemClick",function(a){var c=this.innerId(a);switch(c){case "today":this.setDate(new Date);break;case "add":if(this.innerId(this.$$("views").getActive())=="form"){var d=this;dhx.confirm({height:scheduler.xy.confirm_height,width:scheduler.xy.confirm_width,title:scheduler.locale.labels.icon_close,message:scheduler.locale.labels.confirm_closing,callback:function(a){a&&d.jc()},labelOk:scheduler.locale.labels.icon_yes,labelCancel:scheduler.locale.labels.icon_no,
|
||||
css:"confirm"})}else this.jc();break;case "prev":this.setDate(null,-1,"day");break;case "next":this.setDate(null,1,"day");break;case "edit":this.$$("delete")&&this.$$("delete").show();this.define("editEvent",!0);this.$$("form").show();break;case "back":this.$$("views").back();break;case "cancel":this.callEvent("onAfterCursorChange",[this.getCursor()]);this.$$("views").back();break;case "save":if(this.$$("editForm").validate()){if(this.a.editEvent)this.$$("editForm").save();else{var e=this.$$("editForm").getValues();
|
||||
e.id=dhx.uid();this.add(e);this.setCursor(e.id)}dhx.dp(this).save();this.setDate();this.$$("views").back()}break;case "delete":this.Rd()}});this.attachEvent("onAfterTabClick",function(a,c){this.$$(c).show()});this.attachEvent("onBeforeTabClick",function(a,c){return this.Jd(c)})},readonly_setter:function(a){this.$$("add")&&(a?(this.$$("bottomBar").showBatch("readonly"),this.$$("add").hide(),this.$$("edit").hide()):(this.$$("bottomBar").showBatch("default"),this.$$("add").show(),this.$$("edit").show()));
|
||||
return a},$e:function(){this.dataCount()?this.b.className=this.b.className.replace(RegExp(this.type.cssNoEvents,"g"),""):this.b.className+=" "+this.type.cssNoEvents},Rd:function(){var a=this;dhx.confirm({height:scheduler.xy.confirm_height,width:scheduler.xy.confirm_width,title:scheduler.locale.labels.icon_delete,message:scheduler.locale.labels.confirm_deleting,callback:function(c){c&&(a.remove(a.getCursor()),a.$$("views").back(2))},labelOk:scheduler.locale.labels.icon_yes,labelCancel:scheduler.locale.labels.icon_no,
|
||||
css:"confirm",header:!1})},jc:function(){this.$$("delete")&&this.$$("delete").hide();this.define("editEvent",!1);this.$$("form").show();var a=dhx.Date.add(new Date,1,"hour"),c=new Date(a.setMinutes(0)),d=dhx.Date.add(c,1,"hour");this.$$("editForm").clear();this.$$("editForm").setValues({start_date:c,end_date:d})},Jd:function(a){if(this.innerId(this.$$("views").getActive())=="form"){var c=this;a!="today"&&dhx.confirm({height:scheduler.xy.confirm_height,width:scheduler.xy.confirm_width,title:scheduler.locale.labels.icon_close,
|
||||
message:scheduler.locale.labels.confirm_closing,callback:function(d){d&&(c.$$(a).show(),c.$$("buttons").setValue(a))},labelOk:scheduler.locale.labels.icon_yes,labelCancel:scheduler.locale.labels.icon_no,css:"confirm"});return!1}return!0},re:function(a){var c=a[0].data=dhx.copy(a[0].data);c.start_date=dhx.i18n.fullDateFormatStr(c.start_date);c.end_date=dhx.i18n.fullDateFormatStr(c.end_date)}},dhx.IdSpace,dhx.DataLoader,dhx.ui.layout,dhx.EventSystem,dhx.Settings)});
|
||||
dhx.protoUI({name:"dayevents",defaults:{hourFormat:"%H",hourClock:12,firstHour:0,lastHour:24,timeScaleWidth:45,timeScaleHeight:30,scroll:!0,scaleBorder:1,eventOffset:5,width:"auto",date:new Date},$init:function(a){this.name="DayEvents";this.d.style.position="relative";this.data.provideApi(this,!0);this.data.attachEvent("onStoreUpdated",dhx.bind(this.render,this));this.attachEvent("onBeforeRender",function(){this.Be();this.type.color=this.config.color;this.type.textColor=this.config.textColor;this.De=
|
||||
this.d.firstChild;this.we();if(window.scheduler)this.type.template=scheduler.templates.day_event});if(window.scheduler)a.hourFormat=scheduler.config.scale_hour,a.timeScaleWidth=scheduler.xy.scale_width,a.timeScaleHeight=scheduler.xy.scale_height*2},Be:function(){for(var a="<div></div>",b=this.config.firstHour;b<this.config.lastHour;b++)a+=this.hourScaleItem(b);this.d.innerHTML=a},ma:"dhx_l_id",on_click:{},hourScaleItem:function(a){var b=scheduler.config.hour_date.toLowerCase().indexOf("a")!=-1,c=
|
||||
"00",d="30";b&&(a===0&&(c="AM"),a==12&&(c="PM"),a=(a+11)%12+1);this.config.hourFormat.indexOf("H")!=-1&&(a=dhx.math.toFixed(a));var e="",f=this.config.timeScaleWidth,g=this.config.timeScaleHeight,h=Math.floor(this.config.timeScaleWidth/2),i=Math.floor(g/2),j=i-this.config.scaleBorder,k=this.j-this.config.scaleBorder-this.config.timeScaleWidth;e+="<div style='width: 100%; height:"+g+"px;' class='dhx_dayevents_scale_item'>";e+="<div class='dhx_dayevents_scale_hour' style='width:"+h+"px; height:"+g+
|
||||
"px;line-height:"+g+"px;'>"+a+"</div>";e+="<div class='dhx_dayevents_scale_minute' style='width:"+h+"px'>";e+="<div class='dhx_dayevents_scale_top' style='width:"+h+"px;line-height:"+i+"px'>"+c+"</div>";e+="<div class='dhx_dayevents_scale_bottom' style='width:"+h+"px;line-height:"+j+"px'>"+d+"</div>";e+="</div>";e+="<div class='dhx_dayevents_scale_event' style='width:"+k+"px'>";e+="<div class='dhx_dayevents_scale_top' style='height:"+i+"px;width:"+k+"px'></div>";e+="<div class='dhx_dayevents_scale_bottom' style='width: "+
|
||||
k+"px;height:"+j+"px; '></div>";e+="</div>";e+="</div>";return e},type:{templateStart:dhx.Template("<div dhx_l_id='#id#' class='dhx_dayevents_event_item {common.templateCss()}' style='left:#$left#px;top:#$top#px;width:#$width#px;height:#$height#px;padding:{common.padding}px;overflow:hidden; background-color:{common.templateColor()} ;color:{common.templateTextColor()};'>"),template:scheduler.templates.day_event,templateEnd:dhx.Template("</div>"),templateCss:dhx.Template(""),templateColor:dhx.Template("#color#"),
|
||||
templateTextColor:dhx.Template("#textColor#"),padding:2},we:function(){var a=this.data.getRange(),b=[],c,d,e,f,g;for(d=0;d<a.length;d++){c=a[d];for(c.$inner=!1;b.length&&b[b.length-1].end_date.valueOf()<=c.start_date.valueOf();)b.splice(b.length-1,1);g=!1;for(e=0;e<b.length;e++)if(b[e].end_date.valueOf()<=c.start_date.valueOf()){g=!0;c.$sorder=b[e].$sorder;b.splice(e,1);c.$inner=!0;break}if(b.length)b[b.length-1].$inner=!0;if(!g)if(b.length)if(b.length<=b[b.length-1].$sorder){if(b[b.length-1].$sorder)for(e=
|
||||
0;e<b.length;e++){g=!1;for(f=0;f<b.length;f++)if(b[f].$sorder==e){g=!0;break}if(!g){c.$sorder=e;break}}else c.$sorder=0;c.$inner=!0}else{g=b[0].$sorder;for(e=1;e<b.length;e++)if(b[e].$sorder>g)g=b[e].$sorder;c.$sorder=g+1;c.$inner=!1}else c.$sorder=0;b.push(c);if(b.length>(b.max_count||0))b.max_count=b.length}for(d=0;d<a.length;d++)a[d].$count=b.max_count,this.cc(a[d])},cc:function(a){var b=this.config.date.getValue?this.config.date.getValue():this.config.date,c=dhx.Date.copy(a.start_date),d=dhx.Date.copy(a.end_date),
|
||||
e=c.getHours(),f=d.getHours();dhx.Date.datePart(c).valueOf()>dhx.Date.datePart(d).valueOf()&&(d=c);dhx.Date.datePart(c).valueOf()<dhx.Date.datePart(b).valueOf()&&(c=dhx.Date.datePart(b));dhx.Date.datePart(d).valueOf()>dhx.Date.datePart(b).valueOf()&&(d=dhx.Date.datePart(b),d.setMinutes(0),d.setHours(this.config.lastHour));if(e<this.config.firstHour||f>=this.config.lastHour)e<this.config.firstHour&&(d.setHours(this.config.firstHour),a.start_date.setMinutes(0)),f>=this.config.lastHour&&(d.setMinutes(0),
|
||||
d.setHours(this.config.lastHour));var g=Math.floor((this.j-this.config.timeScaleWidth-this.config.eventOffset-8)/a.$count);a.$left=a.$sorder*g+this.config.timeScaleWidth+this.config.eventOffset;a.$inner||(g*=a.$count-a.$sorder);a.$width=g-this.config.eventOffset-this.type.padding*2;var h=c.getHours()*60+c.getMinutes(),i=d.getHours()*60+d.getMinutes()||this.config.lastHour*60;a.$top=Math.round((h-this.config.firstHour/60)*(this.config.timeScaleHeight+1)/60);a.$height=Math.max(10,(i-h)*(this.config.timeScaleHeight+
|
||||
1)/60-2)-this.type.padding*2}},dhx.MouseEvents,dhx.SelectionModel,dhx.Scrollable,dhx.RenderStack,dhx.DataLoader,dhx.ui.view,dhx.EventSystem,dhx.Settings);
|
|
@ -1,9 +1,6 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){var B=scheduler.date.str_to_date(scheduler.config.api_date);var C=scheduler.date.date_to_str(scheduler.config.api_date);var D=scheduler.templates.month_day;scheduler.templates.month_day=function(E){return"<a jump_to='"+C(E)+"' href='#'>"+D(E)+"</a>"};var A=scheduler.templates.week_scale_date;scheduler.templates.week_scale_date=function(E){return"<a jump_to='"+C(E)+"' href='#'>"+A(E)+"</a>"};dhtmlxEvent(this._obj,"click",function(E){var G=E.target||event.srcElement;var F=G.getAttribute("jump_to");if(F){scheduler.setCurrentView(B(F),"day")}})});
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){var d=scheduler.date.str_to_date(scheduler.config.api_date),b=scheduler.date.date_to_str(scheduler.config.api_date),e=scheduler.templates.month_day;scheduler.templates.month_day=function(a){return"<a jump_to='"+b(a)+"' href='#'>"+e(a)+"</a>"};var f=scheduler.templates.week_scale_date;scheduler.templates.week_scale_date=function(a){return"<a jump_to='"+b(a)+"' href='#'>"+f(a)+"</a>"};dhtmlxEvent(this._obj,"click",function(a){var b=a.target||event.srcElement,
|
||||
c=b.getAttribute("jump_to");if(c)return scheduler.setCurrentView(d(c),"day"),a&&a.preventDefault&&a.preventDefault(),!1})});
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.date.add_agenda=function(A){return(new Date(A.valueOf()))};scheduler.dblclick_dhx_agenda_area=function(){if(!this.config.readonly&&this.config.dblclick_create){this.addEventNow()}};scheduler.templates.agenda_time=function(C,A,B){if(B._timed){return this.day_date(B.start_date,B.end_date,B)+" "+this.event_date(C)}else{return scheduler.templates.day_date(C)+" – "+scheduler.templates.day_date(A)}};scheduler.templates.agenda_text=function(A){return A.text};scheduler.date.agenda_start=function(A){return A};scheduler.attachEvent("onTemplatesReady",function(){scheduler.attachEvent("onSchedulerResize",function(){if(this._mode=="agenda"){this.agenda_view(true);return false}return true});var A=scheduler.render_data;scheduler.render_data=function(D){if(this._mode=="agenda"){B()}else{return A.apply(this,arguments)}};function C(E){if(E){var D=scheduler.locale.labels;scheduler._els.dhx_cal_header[0].innerHTML="<div class='dhx_agenda_line'><div>"+D.date+"</div><span style='padding-left:25px'>"+D.description+"</span></div>";scheduler._table_view=true;scheduler.set_sizes()}}function B(){var D=scheduler._date;var H=scheduler.get_visible_events();H.sort(function(J,I){return J.start_date>I.start_date?1:-1});var G="<div class='dhx_agenda_area'>";for(var F=0;F<H.length;F++){G+="<div class='dhx_agenda_line' event_id='"+H[F].id+"' style='"+(H[F]._text_style||"")+"'><div>"+scheduler.templates.agenda_time(H[F].start_date,H[F].end_date,H[F])+"</div>";G+="<div class='dhx_event_icon icon_details'> </div>";G+="<span>"+scheduler.templates.agenda_text(H[F])+"</span></div>"}G+="<div class='dhx_v_border'></div></div>";scheduler._els.dhx_cal_data[0].scrollTop=0;scheduler._els.dhx_cal_data[0].innerHTML=G;var E=scheduler._els.dhx_cal_data[0].firstChild.childNodes;scheduler._els.dhx_cal_date[0].innerHTML="";scheduler._rendered=[];for(var F=0;F<E.length-1;F++){scheduler._rendered[F]=E[F]}}scheduler.agenda_view=function(D){scheduler._min_date=scheduler.config.agenda_start||(new Date());scheduler._max_date=scheduler.config.agenda_end||(new Date(9999,1,1));scheduler._table_view=true;C(D);if(D){B()}else{}}});
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.date.add_agenda=function(b){return new Date(b.valueOf())};scheduler.dblclick_dhx_agenda_area=function(){!this.config.readonly&&this.config.dblclick_create&&this.addEventNow()};scheduler.templates.agenda_time=function(b,d,a){return a._timed?this.day_date(a.start_date,a.end_date,a)+" "+this.event_date(b):scheduler.templates.day_date(b)+" – "+scheduler.templates.day_date(d)};scheduler.templates.agenda_text=function(b,d,a){return a.text};scheduler.date.agenda_start=function(b){return b};
|
||||
scheduler.attachEvent("onTemplatesReady",function(){function b(b){if(b){var a=scheduler.locale.labels;scheduler._els.dhx_cal_header[0].innerHTML="<div class='dhx_agenda_line'><div>"+a.date+"</div><span style='padding-left:25px'>"+a.description+"</span></div>";scheduler._table_view=!0;scheduler.set_sizes()}}function d(){var b=scheduler._date,a=scheduler.get_visible_events();a.sort(function(a,b){return a.start_date>b.start_date?1:-1});for(var d="<div class='dhx_agenda_area'>",e=0;e<a.length;e++){var c=
|
||||
a[e],f=c.color?"background-color:"+c.color+";":"",h=c.textColor?"color:"+c.textColor+";":"";d+="<div class='dhx_agenda_line' event_id='"+c.id+"' style='"+h+""+f+""+(c._text_style||"")+"'><div>"+scheduler.templates.agenda_time(c.start_date,c.end_date,c)+"</div>";d+="<div class='dhx_event_icon icon_details'> </div>";d+="<span>"+scheduler.templates.agenda_text(c.start_date,c.end_date,c)+"</span></div>"}d+="<div class='dhx_v_border'></div></div>";scheduler._els.dhx_cal_data[0].innerHTML=d;scheduler._els.dhx_cal_data[0].childNodes[0].scrollTop=
|
||||
scheduler._agendaScrollTop||0;var g=scheduler._els.dhx_cal_data[0].firstChild.childNodes;scheduler._els.dhx_cal_date[0].innerHTML="";scheduler._rendered=[];for(e=0;e<g.length-1;e++)scheduler._rendered[e]=g[e]}scheduler.attachEvent("onSchedulerResize",function(){return this._mode=="agenda"?(this.agenda_view(!0),!1):!0});var a=scheduler.render_data;scheduler.render_data=function(b){if(this._mode=="agenda")d();else return a.apply(this,arguments)};var f=scheduler.render_view_data;scheduler.render_view_data=
|
||||
function(){this._mode=="agenda"?(scheduler._agendaScrollTop=scheduler._els.dhx_cal_data[0].childNodes[0].scrollTop,scheduler._els.dhx_cal_data[0].childNodes[0].scrollTop=0,scheduler._els.dhx_cal_data[0].style.overflowY="hidden"):scheduler._els.dhx_cal_data[0].style.overflowY="auto";return f.apply(this,arguments)};scheduler.agenda_view=function(a){scheduler._min_date=scheduler.config.agenda_start||new Date;scheduler._max_date=scheduler.config.agenda_end||new Date(9999,1,1);scheduler._table_view=!0;
|
||||
b(a);a&&d()}});
|
||||
|
|
|
@ -1 +1,8 @@
|
|||
(function(){var C,D;var B;scheduler.config.collision_limit=1;scheduler.attachEvent("onBeforeDrag",function(I){var H=scheduler._props?scheduler._props[this._mode]:null;var F=scheduler.matrix?scheduler.matrix[this._mode]:null;var G=H||F;if(H){var E=G.map_to}if(F){var E=G.y_property}if((G)&&I){C=this.getEvent(I)[E];D=this.getEvent(I).start_date}return true});scheduler.attachEvent("onBeforeLightbox",function(F){var E=scheduler.getEvent(F);B=[E.start_date,E.end_date];return true});scheduler.attachEvent("onEventChanged",function(F){if(!F){return true}var E=scheduler.getEvent(F);if(!A(E)){if(!B){return false}E.start_date=B[0];E.end_date=B[1];E._timed=this.is_one_day_event(E)}return true});scheduler.attachEvent("onBeforeEventChanged",function(E,F,G){return A(E)});scheduler.attachEvent("onEventSave",function(F,E){if(E.rec_type){scheduler._roll_back_dates(E)}return A(E)});function A(N){var Q=[];if(N.rec_type){var F=scheduler.getRecDates(N);for(var I=0;I<F.length;I++){var M=scheduler.getEvents(F[I].start_date,F[I].end_date);for(var J=0;J<M.length;J++){if((M[J].event_pid||M[J].id)!=N.id){Q.push(M[J])}}}Q.push(N)}else{Q=scheduler.getEvents(N.start_date,N.end_date)}var E=scheduler._props?scheduler._props[scheduler._mode]:null;var O=scheduler.matrix?scheduler.matrix[scheduler._mode]:null;var H=E||O;if(E){var G=H.map_to}if(O){var G=H.y_property}var P=true;if(H){var L=0;for(var K=0;K<Q.length;K++){if(Q[K][G]==N[G]){L++}}if(L>scheduler.config.collision_limit){scheduler._drag_event.start_date=D;N[G]=C;P=false}}else{if(Q.length>scheduler.config.collision_limit){P=false}}if(!P){return !scheduler.callEvent("onEventCollision",[N,Q])}return P}})();
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
(function(){function h(a){var b=scheduler._props?scheduler._props[scheduler._mode]:null,f=scheduler.matrix?scheduler.matrix[scheduler._mode]:null,c=b||f;if(b)var d=c.map_to;if(f)d=c.y_property;c&&a&&(n=scheduler.getEvent(a)[d])}function g(a){var b=[];if(a.rec_type){for(var f=scheduler.getRecDates(a),c=0;c<f.length;c++)for(var d=scheduler.getEvents(f[c].start_date,f[c].end_date),i=0;i<d.length;i++)(d[i].event_pid||d[i].id)!=a.id&&b.push(d[i]);b.push(a)}else b=scheduler.getEvents(a.start_date,a.end_date);
|
||||
var e=scheduler._props?scheduler._props[scheduler._mode]:null,g=scheduler.matrix?scheduler.matrix[scheduler._mode]:null,m=e||g;if(e)var j=m.map_to;if(g)j=m.y_property;var k=!0;if(m){for(var h=0,l=0;l<b.length;l++)b[l][j]==a[j]&&b[l].id!=a.id&&h++;h>=scheduler.config.collision_limit&&(a[j]=n,k=!1)}else b.length>scheduler.config.collision_limit&&(k=!1);return!k?!scheduler.callEvent("onEventCollision",[a,b]):k}var n,e;scheduler.config.collision_limit=1;scheduler.attachEvent("onBeforeDrag",function(a){h(a);
|
||||
return!0});scheduler.attachEvent("onBeforeLightbox",function(a){var b=scheduler.getEvent(a);e=[b.start_date,b.end_date];h(a);return!0});scheduler.attachEvent("onEventChanged",function(a){if(!a)return!0;var b=scheduler.getEvent(a);if(!g(b)){if(!e)return!1;b.start_date=e[0];b.end_date=e[1];b._timed=this.is_one_day_event(b)}return!0});scheduler.attachEvent("onBeforeEventChanged",function(a){return g(a)});scheduler.attachEvent("onEventSave",function(a,b){return b.rec_type?(scheduler._roll_back_dates(b),
|
||||
g(b)):!0})})();
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
(function(){function B(E,D,F){var G=E+"="+F+(D?("; "+D):"");document.cookie=G}function A(E){var F=E+"=";if(document.cookie.length>0){var G=document.cookie.indexOf(F);if(G!=-1){G+=F.length;var D=document.cookie.indexOf(";",G);if(D==-1){D=document.cookie.length}return document.cookie.substring(G,D)}}return""}var C=true;scheduler.attachEvent("onBeforeViewChange",function(F,E,D,I){if(C){C=false;var G=A("scheduler_settings");if(G){G=G.split("@");G[0]=this.templates.xml_date(G[0]);this.setCurrentView(G[0],G[1]);return false}}var H=this.templates.xml_format(I||E)+"@"+(D||F);B("scheduler_settings","expires=Sun, 31 Jan 9999 22:00:00 GMT",H);return true})})();
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
(function(){function g(e,b,a){var c=e+"="+a+(b?"; "+b:"");document.cookie=c}function h(e){var b=e+"=";if(document.cookie.length>0){var a=document.cookie.indexOf(b);if(a!=-1){a+=b.length;var c=document.cookie.indexOf(";",a);if(c==-1)c=document.cookie.length;return document.cookie.substring(a,c)}}return""}var f=!0;scheduler.attachEvent("onBeforeViewChange",function(e,b,a,c){if(f){f=!1;var d=h("scheduler_settings");if(d)return d=d.split("@"),d[0]=this.templates.xml_date(d[0]),this.setCurrentView(d[0],
|
||||
d[1]),!1}var i=this.templates.xml_format(c||b)+"@"+(a||e);g("scheduler_settings","expires=Sun, 31 Jan 9999 22:00:00 GMT",i);return!0})})();
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.form_blocks.combo={render:function(B){var A="";A+="<div class='"+B.type+"' style='height:"+(B.height||20)+"px;' ></div>";return A},set_value:function(F,H,E,C){if(F._combo){F._combo.destructor()}window.dhx_globalImgPath=C.image_path||"/";F._combo=new dhtmlXCombo(F,C.name,F.offsetWidth-8);F._combo.enableFilteringMode(!!C.filtering,C.script_path||null,!!C.cache);if(!C.script_path){var G=[];for(var D=0;D<C.options.length;D++){var A=[];A.push(C.options[D].key);A.push(C.options[D].label);G.push(A)}F._combo.addOption(G);if(E[C.map_to]){var B=F._combo.getIndexByValue(E[C.map_to]);F._combo.selectOption(B)}}else{F._combo.setComboValue(E[C.map_to]||null)}},get_value:function(D,C,A){var B=D._combo.getSelectedValue();return B},focus:function(A){}};scheduler.form_blocks.radio={render:function(C){var B="";B+="<div class='"+C.type+"' style='height:"+C.height+"px;' >";for(var A=0;A<C.options.length;A++){var D=scheduler.uid();B+="<input id='"+D+"' type='radio' name='"+C.name+"' value='"+C.options[A].key+"'><label for='"+D+"'> "+C.options[A].label+"</label>";if(C.vertical){B+="<br/>"}}B+="</div>";return B},set_value:function(D,F,C,A){var E=D.getElementsByTagName("input");for(var B=0;B<E.length;B++){E[B].checked=false;if(E[B].value==C[A.map_to]){E[B].checked=true}}},get_value:function(D,C,A){var E=D.getElementsByTagName("input");for(var B=0;B<E.length;B++){if(E[B].checked){return E[B].value}}},focus:function(A){}};scheduler.form_blocks.checkbox={render:function(A){return""},set_value:function(C,D,B,A){var F=scheduler.uid();var E=false;if(typeof A.checked_value!="undefined"&&B[A.map_to]==A.checked_value){E=true}C.previousSibling.className+=" dhx_cal_checkbox";C.previousSibling.innerHTML="<input id='"+F+"' type='checkbox' value='true' name='"+A.name+"'"+((E)?"checked='true'":"")+"'><label for='"+F+"'>"+(scheduler.locale.labels["section_"+A.name]||A.name)+"</label>"},get_value:function(C,B,A){var D=C.previousSibling.getElementsByTagName("input")[0];return(D.checked)?(A.checked_value||true):(A.unchecked_value||false)},focus:function(A){}};
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.form_blocks.combo={render:function(a){var d="";d+="<div class='"+a.type+"' style='height:"+(a.height||20)+"px;' ></div>";return d},set_value:function(a,d,c,b){a._combo&&a._combo.destructor();window.dhx_globalImgPath=b.image_path||"/";a._combo=new dhtmlXCombo(a,b.name,a.offsetWidth-8);a._combo.enableFilteringMode(!!b.filtering,b.script_path||null,!!b.cache);if(b.script_path)a._combo.setComboValue(c[b.map_to]||null);else{for(var f=[],e=0;e<b.options.length;e++){var g=[];g.push(b.options[e].key);
|
||||
g.push(b.options[e].label);f.push(g)}a._combo.addOption(f);if(c[b.map_to]){var h=a._combo.getIndexByValue(c[b.map_to]);a._combo.selectOption(h)}}},get_value:function(a){var d=a._combo.getSelectedValue();return d},focus:function(){}};
|
||||
scheduler.form_blocks.radio={render:function(a){var d="";d+="<div class='dhx_cal_ltext dhx_cal_radio' style='height:"+a.height+"px;' >";for(var c=0;c<a.options.length;c++){var b=scheduler.uid();d+="<input id='"+b+"' type='radio' name='"+a.name+"' value='"+a.options[c].key+"'><label for='"+b+"'> "+a.options[c].label+"</label>";a.vertical&&(d+="<br/>")}d+="</div>";return d},set_value:function(a,d,c,b){for(var f=a.getElementsByTagName("input"),e=0;e<f.length;e++)if(f[e].checked=!1,f[e].value==c[b.map_to])f[e].checked=
|
||||
!0},get_value:function(a){for(var d=a.getElementsByTagName("input"),c=0;c<d.length;c++)if(d[c].checked)return d[c].value},focus:function(){}};
|
||||
scheduler.form_blocks.checkbox={render:function(){return scheduler.config.wide_form?'<div class="dhx_cal_wide_checkbox"></div>':""},set_value:function(a,d,c,b){var a=document.getElementById(b.id),f=scheduler.uid(),e=!1;typeof b.checked_value!="undefined"&&c[b.map_to]==b.checked_value&&(e=!0);a.className+=" dhx_cal_checkbox";var g="<input id='"+f+"' type='checkbox' value='true' name='"+b.name+"'"+(e?"checked='true'":"")+"'>",h="<label for='"+f+"'>"+(scheduler.locale.labels["section_"+b.name]||b.name)+
|
||||
"</label>";scheduler.config.wide_form?(a.innerHTML=h,a.nextSibling.innerHTML=g):a.innerHTML=g+h},get_value:function(a,d,c){var a=document.getElementById(c.id),b=a.getElementsByTagName("input")[0];b||(b=a.nextSibling.getElementsByTagName("input")[0]);return b.checked?c.checked_value||!0:c.unchecked_value||!1},focus:function(){}};
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.expand=function(){var A=scheduler._obj;do{A._position=A.style.position||"";A.style.position="static"}while((A=A.parentNode)&&A.style);A=scheduler._obj;A.style.position="absolute";A._width=A.style.width;A._height=A.style.height;A.style.width=A.style.height="100%";A.style.top=A.style.left="0px";var B=document.body;B.scrollTop=0;B=B.parentNode;if(B){B.scrollTop=0}document.body._overflow=document.body.style.overflow||"";document.body.style.overflow="hidden";scheduler._maximize()};scheduler.collapse=function(){var A=scheduler._obj;do{A.style.position=A._position}while((A=A.parentNode)&&A.style);A=scheduler._obj;A.style.width=A._width;A.style.height=A._height;document.body.style.overflow=document.body._overflow;scheduler._maximize()};scheduler.attachEvent("onTemplatesReady",function(){var A=document.createElement("DIV");A.className="dhx_expand_icon";scheduler.toggleIcon=A;scheduler._obj.appendChild(A);A.onclick=function(){if(!scheduler.expanded){scheduler.expand()}else{scheduler.collapse()}}});scheduler._maximize=function(){this.expanded=!this.expanded;this.toggleIcon.style.backgroundPosition="0px "+(this._expand?"0":"18")+"px";if(scheduler.callEvent("onSchedulerResize",[])){scheduler.update_view()}};
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.expand=function(){var a=scheduler._obj;do a._position=a.style.position||"",a.style.position="static";while((a=a.parentNode)&&a.style);a=scheduler._obj;a.style.position="absolute";a._width=a.style.width;a._height=a.style.height;a.style.width=a.style.height="100%";a.style.top=a.style.left="0px";var b=document.body;b.scrollTop=0;if(b=b.parentNode)b.scrollTop=0;document.body._overflow=document.body.style.overflow||"";document.body.style.overflow="hidden";scheduler._maximize()};
|
||||
scheduler.collapse=function(){var a=scheduler._obj;do a.style.position=a._position;while((a=a.parentNode)&&a.style);a=scheduler._obj;a.style.width=a._width;a.style.height=a._height;document.body.style.overflow=document.body._overflow;scheduler._maximize()};scheduler.attachEvent("onTemplatesReady",function(){var a=document.createElement("DIV");a.className="dhx_expand_icon";scheduler.toggleIcon=a;scheduler._obj.appendChild(a);a.onclick=function(){scheduler.expanded?scheduler.collapse():scheduler.expand()}});
|
||||
scheduler._maximize=function(){this.expanded=!this.expanded;this.toggleIcon.style.backgroundPosition="0px "+(this.expanded?"0":"18")+"px";for(var a=["left","top"],b=0;b<a.length;b++){var d=scheduler.xy["margin_"+a[b]],c=scheduler["_prev_margin_"+a[b]];scheduler.xy["margin_"+a[b]]?(scheduler["_prev_margin_"+a[b]]=scheduler.xy["margin_"+a[b]],scheduler.xy["margin_"+a[b]]=0):c&&(scheduler.xy["margin_"+a[b]]=scheduler["_prev_margin_"+a[b]],delete scheduler["_prev_margin_"+a[b]])}scheduler.callEvent("onSchedulerResize",
|
||||
[])&&scheduler.update_view()};
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){var B=document.body.getElementsByTagName("DIV");for(var A=0;A<B.length;A++){var C=B[A].className||"";C=C.split(":");if(C.length==2&&C[0]=="template"){var D='return "'+(B[A].innerHTML||"").replace(/\"/g,'\\"').replace(/[\n\r]+/g,"")+'";';D=unescape(D).replace(/\{event\.([a-z]+)\}/g,function(F,E){return'"+ev.'+E+'+"'});scheduler.templates[C[1]]=Function("start","end","ev",D);B[A].style.display="none"}}});
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){for(var c=document.body.getElementsByTagName("DIV"),b=0;b<c.length;b++){var a=c[b].className||"",a=a.split(":");if(a.length==2&&a[0]=="template"){var d='return "'+(c[b].innerHTML||"").replace(/\"/g,'\\"').replace(/[\n\r]+/g,"")+'";',d=unescape(d).replace(/\{event\.([a-z]+)\}/g,function(b,a){return'"+ev.'+a+'+"'});scheduler.templates[a[1]]=Function("start","end","ev",d);c[b].style.display="none"}}});
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
(function(){var A=false;scheduler.attachEvent("onBeforeLightbox",function(){A=true;return true});scheduler.attachEvent("onAfterLightbox",function(){A=false;return true});dhtmlxEvent(document,(_isOpera?"keypress":"keydown"),function(D){D=D||event;if(!A){if(D.keyCode==37||D.keyCode==39){D.cancelBubble=true;var B=scheduler.date.add(scheduler._date,(D.keyCode==37?-1:1),scheduler._mode);scheduler.setCurrentView(B);return true}else{if(D.ctrlKey&&D.keyCode==67){scheduler._copy_id=scheduler._select_id}else{if(D.ctrlKey&&D.keyCode==86){var C=scheduler.getEvent(scheduler._copy_id);if(C){var E=scheduler._copy_event(C);E.id=scheduler.uid();scheduler.addEvent(E)}}}}}})})();
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
(function(){var b=!1;scheduler.attachEvent("onBeforeLightbox",function(){return b=!0});scheduler.attachEvent("onAfterLightbox",function(){b=!1;return!0});dhtmlxEvent(document,_isOpera?"keypress":"keydown",function(a){a=a||event;if(!b)if(a.keyCode==37||a.keyCode==39){a.cancelBubble=!0;var e=scheduler.date.add(scheduler._date,a.keyCode==37?-1:1,scheduler._mode);scheduler.setCurrentView(e);return!0}else if(a.ctrlKey&&a.keyCode==67)scheduler._copy_id=scheduler._select_id;else if(a.ctrlKey&&a.keyCode==
|
||||
86){var c=scheduler.getEvent(scheduler._copy_id);if(c){var d=scheduler._copy_event(c);d.id=scheduler.uid();scheduler.addEvent(d)}}})})();
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.config.limit_start=new Date(-3999,0,0);scheduler.config.limit_end=new Date(3999,0,0);scheduler.config.limit_view=false;(function(){var B=null;scheduler.attachEvent("onBeforeViewChange",function(E,D,C,F){F=F||D;C=C||E;if(scheduler.config.limit_view){if(F.valueOf()>scheduler.config.limit_end.valueOf()||this.date.add(F,1,C)<=scheduler.config.limit_start.valueOf()){setTimeout(function(){scheduler.setCurrentView(scheduler._date,C)},1);return false}}return true});var A=function(D){var E=scheduler.config;var C=(D.start_date.valueOf()>=E.limit_start.valueOf()&&D.end_date.valueOf()<=E.limit_end.valueOf());if(!C){scheduler._drag_id=null;scheduler._drag_mode=null;scheduler.callEvent("onLimitViolation",[D.id,D])}return C};scheduler.attachEvent("onBeforeDrag",function(C){if(!C){return true}return A(scheduler.getEvent(C))});scheduler.attachEvent("onClick",function(D,C){return A(scheduler.getEvent(D))});scheduler.attachEvent("onBeforeLightbox",function(D){var C=scheduler.getEvent(D);B=[C.start_date,C.end_date];return A(C)});scheduler.attachEvent("onEventAdded",function(D){if(!D){return true}var C=scheduler.getEvent(D);if(!A(C)){if(C.start_date<scheduler.config.limit_start){C.start_date=new Date(scheduler.config.limit_start)}if(C.end_date>scheduler.config.limit_end){C.end_date=new Date(scheduler.config.limit_end);C._timed=this.is_one_day_event(C)}if(C.start_date>C.end_date){C.end_date=this.date.add(C.start_date,(this.config.event_duration||this.config.time_step),"minute")}}return true});scheduler.attachEvent("onEventChanged",function(D){if(!D){return true}var C=scheduler.getEvent(D);if(!A(C)){if(!B){return false}C.start_date=B[0];C.end_date=B[1];C._timed=this.is_one_day_event(C)}return true});scheduler.attachEvent("onBeforeEventChanged",function(D,C,E){return A(D)})})();
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.config.limit_start=new Date(-3999,0,0);scheduler.config.limit_end=new Date(3999,0,0);scheduler.config.limit_view=!1;
|
||||
(function(){var g=null,k={},l={},m=!1;scheduler.blockTime=function(b,a){var c=this.config.first_hour*60,d=this.config.last_hour*60;a=="fullday"&&(a=[c,d]);typeof b=="object"?k[this.date.date_part(b).valueOf()]=a:l[b]=a;for(var e=0;e<a.length;e+=2)a[e]<c&&(a[e]=c),a[e+1]>d&&(a[e+1]=d);m=!0};scheduler.attachEvent("onScaleAdd",function(b,a){var c=k[a.valueOf()]||l[a.getDay()];if(c)for(var d=0;d<c.length;d+=2){var e=c[d],f=c[d+1],h=document.createElement("DIV");h.className="dhx_time_block";var j;h.style.top=
|
||||
Math.round((e*6E4-this.config.first_hour*36E5)*this.config.hour_size_px/36E5)%(this.config.hour_size_px*24)+"px";h.style.height=Math.round((f-e-1)*6E4*this.config.hour_size_px/36E5)%(this.config.hour_size_px*24)+"px";b.appendChild(h)}});scheduler.attachEvent("onBeforeViewChange",function(b,a,c,d){d=d||a;c=c||b;return scheduler.config.limit_view&&(d.valueOf()>scheduler.config.limit_end.valueOf()||this.date.add(d,1,c)<=scheduler.config.limit_start.valueOf())?(setTimeout(function(){scheduler.setCurrentView(scheduler._date,
|
||||
c)},1),!1):!0});var f=function(b){var a=scheduler.config,c=b.start_date.valueOf()>=a.limit_start.valueOf()&&b.end_date.valueOf()<=a.limit_end.valueOf();if(c&&m&&b._timed){var d=scheduler.date.date_part(new Date(b.start_date.valueOf())),e=k[d.valueOf()]||l[d.getDay()],f=b.start_date.getHours()*60+b.start_date.getMinutes(),h=b.end_date.getHours()*60+b.end_date.getMinutes();if(e)for(var j=0;j<e.length;j+=2){var g=e[j],i=e[j+1];if(g<h&&i>f){if(f<=i&&f>=g){if(i==1440||h<i){c=!1;break}if(scheduler._drag_id&&
|
||||
scheduler._drag_mode=="new-size")b.start_date.setHours(0),b.start_date.setMinutes(i);else{c=!1;break}}if(h>=g&&h<i)if(scheduler._drag_id&&scheduler._drag_mode=="new-size")b.end_date.setHours(0),b.end_date.setMinutes(g);else{c=!1;break}}}}if(!c)scheduler._drag_id=null,scheduler._drag_mode=null,scheduler.callEvent("onLimitViolation",[b.id,b]);return c};scheduler.attachEvent("onBeforeDrag",function(b){return!b?!0:f(scheduler.getEvent(b))});scheduler.attachEvent("onClick",function(b){return f(scheduler.getEvent(b))});
|
||||
scheduler.attachEvent("onBeforeLightbox",function(b){var a=scheduler.getEvent(b);g=[a.start_date,a.end_date];return f(a)});scheduler.attachEvent("onEventAdded",function(b){if(!b)return!0;var a=scheduler.getEvent(b);if(!f(a)){if(a.start_date<scheduler.config.limit_start)a.start_date=new Date(scheduler.config.limit_start);if(a.start_date.valueOf()>=scheduler.config.limit_end.valueOf())a.start_date=this.date.add(scheduler.config.limit_end,-1,"day");if(a.end_date<scheduler.config.limit_start)a.end_date=
|
||||
new Date(scheduler.config.limit_start);if(a.end_date.valueOf()>=scheduler.config.limit_end.valueOf())a.end_date=this.date.add(scheduler.config.limit_end,-1,"day");if(a.start_date.valueOf()>=a.end_date.valueOf())a.end_date=this.date.add(a.start_date,this.config.event_duration||this.config.time_step,"minute");a._timed=this.is_one_day_event(a)}return!0});scheduler.attachEvent("onEventChanged",function(b){if(!b)return!0;var a=scheduler.getEvent(b);if(!f(a)){if(!g)return!1;a.start_date=g[0];a.end_date=
|
||||
g[1];a._timed=this.is_one_day_event(a)}return!0});scheduler.attachEvent("onBeforeEventChanged",function(b){return f(b)})})();
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.form_blocks.multiselect={render:function(C){var B="<div class='dhx_multi_select_"+C.name+"' style='overflow: auto; height: "+C.height+"px; position: relative;' >";for(var A=0;A<C.options.length;A++){B+="<label><input type='checkbox' value='"+C.options[A].key+"'/>"+C.options[A].label+"</label>";if(convertStringToBoolean(C.vertical)){B+="<br/>"}}B+="</div>";return B},set_value:function(C,J,I,A){var E=C.getElementsByTagName("input");for(var G=0;G<E.length;G++){E[G].checked=false}function H(M){var L=C.getElementsByTagName("input");for(var K=0;K<L.length;K++){L[K].checked=!!M[L[K].value]}}if(!scheduler._new_event){var D=[];if(I[A.map_to]){var F=I[A.map_to].split(",");for(var G=0;G<F.length;G++){D[F[G]]=true}H(D)}else{var B=document.createElement("div");B.className="dhx_loading";B.style.cssText="position: absolute; top: 40%; left: 40%;";C.appendChild(B);dhtmlxAjax.get(A.script_url+"?dhx_crosslink_"+A.map_to+"="+I.id+"&uid="+scheduler.uid(),function(K){var M=K.doXPath("//data/item");var N=[];for(var L=0;L<M.length;L++){N[M[L].getAttribute(A.map_to)]=true}H(N);C.removeChild(B)})}}},get_value:function(F,E,A){var C=[];var D=F.getElementsByTagName("input");for(var B=0;B<D.length;B++){if(D[B].checked){C.push(D[B].value)}}return C.join(",")},focus:function(A){}};
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.form_blocks.multiselect={render:function(d){for(var a="<div class='dhx_multi_select_"+d.name+"' style='overflow: auto; height: "+d.height+"px; position: relative;' >",b=0;b<d.options.length;b++)a+="<label><input type='checkbox' value='"+d.options[b].key+"'/>"+d.options[b].label+"</label>",convertStringToBoolean(d.vertical)&&(a+="<br/>");a+="</div>";return a},set_value:function(d,a,b,c){function h(b){for(var c=d.getElementsByTagName("input"),a=0;a<c.length;a++)c[a].checked=!!b[c[a].value]}
|
||||
for(var f=d.getElementsByTagName("input"),e=0;e<f.length;e++)f[e].checked=!1;if(!scheduler._new_event)if(f=[],b[c.map_to]){for(var i=b[c.map_to].split(","),e=0;e<i.length;e++)f[i[e]]=!0;h(f)}else{var g=document.createElement("div");g.className="dhx_loading";g.style.cssText="position: absolute; top: 40%; left: 40%;";d.appendChild(g);dhtmlxAjax.get(c.script_url+"?dhx_crosslink_"+c.map_to+"="+b.id+"&uid="+scheduler.uid(),function(b){for(var a=b.doXPath("//data/item"),e=[],f=0;f<a.length;f++)e[a[f].getAttribute(c.map_to)]=
|
||||
!0;h(e);d.removeChild(g)})}},get_value:function(d){for(var a=[],b=d.getElementsByTagName("input"),c=0;c<b.length;c++)b[c].checked&&a.push(b[c].value);return a.join(",")},focus:function(){}};
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
(function(){function B(D){var C=function(){};C.prototype=D;return C}var A=scheduler._load;scheduler._load=function(C,F){C=C||this._load_url;if(typeof C=="object"){var E=B(this._loaded);for(var D=0;D<C.length;D++){this._loaded=new E();A.call(this,C[D],F)}}else{A.apply(this,arguments)}}})();
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
(function(){function e(a){var b=function(){};b.prototype=a;return b}var d=scheduler._load;scheduler._load=function(a,b){a=a||this._load_url;if(typeof a=="object")for(var f=e(this._loaded),c=0;c<a.length;c++)this._loaded=new f,d.call(this,a[c],b);else d.apply(this,arguments)}})();
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler._extra_xle=!1;scheduler.attachEvent("onXLE",function(){if(!scheduler._extra_xle){var a=!1,c;for(c in scheduler._events)if(scheduler._events[c].text){a=!0;break}if((localStorage._updated_events||!a)&&localStorage._events){scheduler._extra_xle=!0;scheduler.parse(localStorage._events,"json");scheduler._extra_xle=!1;var b=scheduler._dataprocessor,e=JSON.parse(localStorage._updated_events);b.setUpdateMode("off");for(var d in e)b.setUpdated(d,!0,e[d]);b.sendData();b.setUpdateMode("cell")}}});
|
||||
scheduler.attachEvent("onBeforeEventDelete",function(a){var c=scheduler._dataprocessor.getState(a);if(c=="inserted"&&localStorage._updated_events){var b=JSON.parse(localStorage._updated_events);delete b[a];for(a in b){localStorage._updated_events=JSON.stringify(b);break}}return!0});var old_delete_event=scheduler.deleteEvent;scheduler.deleteEvent=function(a,c){old_delete_event.apply(this,arguments);localStorage._events=scheduler.toJSON()};scheduler._offline={};
|
||||
scheduler._offline._after_update_events=[];var old_dp_init=scheduler._dp_init;
|
||||
scheduler._dp_init=function(a){old_dp_init.apply(this,arguments);a.attachEvent("onAfterUpdate",function(c){scheduler._offline._after_update_events.push(c);return!0});a.attachEvent("onAfterUpdateFinish",function(){localStorage._events=scheduler.toJSON();for(var c=JSON.parse(localStorage._updated_events),b=0;b<scheduler._offline._after_update_events.length;b++)delete c[scheduler._offline._after_update_events[b]];var a=!1,d;for(d in c){a=!0;break}a?(localStorage._updated_events=JSON.stringify(c),scheduler._offline._after_update_event=
|
||||
[]):delete localStorage._updated_events;return!0});a.attachEvent("onBeforeDataSending",function(a,b,e){var d={};localStorage._updated_events&&(d=JSON.parse(localStorage._updated_events));for(var f in e){var g=scheduler._dataprocessor.action_param;if(d[f]&&(d[f][g]=="inserted"||e[f][g]=="deleted")||!d[f])d[f]=e[f][g]}localStorage._events=scheduler.toJSON();localStorage._updated_events=JSON.stringify(d);return!0});dhtmlxError.catchError("LoadXML",function(){for(var a in scheduler._dataprocessor._in_progress)delete scheduler._dataprocessor._in_progress[a]})};
|
|
@ -1,9 +1,6 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){var C=(new dhtmlDragAndDropObject());var B=C.stopDrag;var A;C.stopDrag=function(D){A=D||event;return B.apply(this,arguments)};C.addDragLanding(scheduler._els.dhx_cal_data[0],{_drag:function(F,G,D){var E=scheduler.attachEvent("onEventCreated",function(I,H){if(!scheduler.callEvent("onExternalDragIn",[I,F,H])){this._drag_mode=this._drag_id=null;this.deleteEvent(I)}});if(scheduler.matrix[scheduler._mode]){scheduler.dblclick_dhx_matrix_cell(A)}else{scheduler._on_dbl_click(A)}scheduler.detachEvent(E)},_dragIn:function(E,D){return E},_dragOut:function(D){return this}})});
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){var a=new dhtmlDragAndDropObject,g=a.stopDrag,b;a.stopDrag=function(d){b=d||event;return g.apply(this,arguments)};a.addDragLanding(scheduler._els.dhx_cal_data[0],{_drag:function(d){var a=scheduler.attachEvent("onEventCreated",function(a,b){if(!scheduler.callEvent("onExternalDragIn",[a,d,b]))this._drag_mode=this._drag_id=null,this.deleteEvent(a)});if(scheduler.matrix&&scheduler.matrix[scheduler._mode])scheduler.dblclick_dhx_matrix_cell(b);else{var f=
|
||||
document.createElement("div");f.className="dhx_month_body";var c={},e;for(e in b)c[e]=b[e];c.target=c.srcElement=f;scheduler._on_dbl_click(c)}scheduler.detachEvent(a)},_dragIn:function(a){return a},_dragOut:function(){return this}})});
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.toPDF=function(C,J,P,L){var I=0;var H=0;var F=false;if(J=="fullcolor"){F=true;J="color"}J=J||"color";function M(T){T=parseFloat(T);if(isNaN(T)){return"auto"}return 100*T/I}function Q(T){T=parseFloat(T);if(isNaN(T)){return"auto"}return 100*T/H}function O(U){var T="";for(var V=0;V<U.length;V++){T+="\n<column><![CDATA["+U[V].innerHTML+"]]></column>"}I=U[0].offsetWidth;return T}function G(V,W){var T=parseInt(V.style.left);for(var U=0;U<scheduler._cols.length;U++){T-=scheduler._cols[U];if(T<0){return U}}return W}function N(U,W){var V=parseInt(U.style.top);for(var T=0;T<scheduler._colsS.heights.length;T++){if(scheduler._colsS.heights[T]>V){return T}}return W}function A(W){var U="";var X=W.firstChild.rows;for(var V=0;V<X.length;V++){var Y=[];for(var T=0;T<X[V].cells.length;T++){Y.push(X[V].cells[T].firstChild.innerHTML)}U+="\n<row height='"+W.firstChild.rows[V].cells[0].offsetHeight+"'><![CDATA["+Y.join("|")+"]]></row>";H=W.firstChild.rows[0].cells[0].offsetHeight}return U}function S(X){var U="<data profile='"+X+"'";if(P){U+=" header='"+P+"'"}if(L){U+=" footer='"+L+"'"}U+=">";U+="<scale mode='"+scheduler._mode+"' today='"+scheduler._els.dhx_cal_date[0].innerHTML+"'>";if(scheduler._mode=="agenda"){var T=scheduler._els.dhx_cal_header[0].childNodes[0].childNodes;U+="<column>"+T[0].innerHTML+"</column><column>"+T[1].innerHTML+"</column>"}else{if(scheduler._mode=="year"){var T=scheduler._els.dhx_cal_data[0].childNodes;for(var V=0;V<T.length;V++){U+="<month label='"+T[V].childNodes[0].innerHTML+"'>";U+=O(T[V].childNodes[1].childNodes);U+=A(T[V].childNodes[2]);U+="</month>"}}else{U+="<x>";var T=scheduler._els.dhx_cal_header[0].childNodes;U+=O(T);U+="</x>";var W=scheduler._els.dhx_cal_data[0];if(W.firstChild.tagName=="TABLE"){U+=A(W)}else{W=W.childNodes[W.childNodes.length-1];while(W.className.indexOf("dhx_scale_holder")==-1){W=W.previousSibling}W=W.childNodes;U+="<y>";for(var V=0;V<W.length;V++){U+="\n<row><![CDATA["+W[V].innerHTML+"]]></row>"}U+="</y>";H=W[0].offsetHeight}}}U+="</scale>";return U}function E(U,T){return(window.getComputedStyle?(window.getComputedStyle(U,null)[T]):(U.currentStyle?U.currentStyle[T]:null))||""}function B(){var b="";var j=scheduler._rendered;if(scheduler._mode=="agenda"){for(var Z=0;Z<j.length;Z++){b+="<event><head>"+j[Z].childNodes[0].innerHTML+"</head><body>"+j[Z].childNodes[2].innerHTML+"</body></event>"}}else{if(scheduler._mode=="year"){var j=scheduler.get_visible_events();for(var Z=0;Z<j.length;Z++){var f=j[Z].start_date;if(f.valueOf()<scheduler._min_date.valueOf()){f=scheduler._min_date}while(f<j[Z].end_date){var U=f.getMonth()+12*(f.getFullYear()-scheduler._min_date.getFullYear())-scheduler.week_starts._month;var g=scheduler.week_starts[U]+f.getDate()-1;b+="<event day='"+(g%7)+"' week='"+Math.floor(g/7)+"' month='"+U+"'></event>";scheduler._mark_year_date(f);f=scheduler.date.add(f,1,"day");if(f.valueOf()>=scheduler._max_date.valueOf()){break}}}}else{for(var Z=0;Z<j.length;Z++){var X=M(j[Z].style.left);var V=Q(j[Z].style.top);var e=M(j[Z].style.width);var a=Q(j[Z].style.height);var Y=j[Z].className.split(" ")[0].replace("dhx_cal_","");var c=scheduler.getEvent(j[Z].getAttribute("event_id"));var g=c._sday;var T=c._sweek;if(scheduler._mode!="month"){if(parseInt(j[Z].style.left)<=26){X=2;e+=M(j[Z].style.left)-1}if(j[Z].parentNode==scheduler._els.dhx_cal_data[0]){continue}X+=M(j[Z].parentNode.style.left);X-=M(51)}else{a=parseInt(j[Z].offsetHeight);V=parseInt(j[Z].style.top)-22;g=G(j[Z],g);T=N(j[Z],T)}b+="\n<event week='"+T+"' day='"+g+"' type='"+Y+"' x='"+X+"' y='"+V+"' width='"+e+"' height='"+a+"'>";if(Y=="event"){b+="<header><![CDATA["+j[Z].childNodes[1].innerHTML+"]]></header>";var W=F?E(j[Z].childNodes[2],"color"):"";var h=F?E(j[Z].childNodes[2],"backgroundColor"):"";b+="<body backgroundColor='"+h+"' color='"+W+"'><![CDATA["+j[Z].childNodes[2].innerHTML+"]]></body>"}else{var W=F?E(j[Z],"color"):"";var h=F?E(j[Z],"backgroundColor"):"";b+="<body backgroundColor='"+h+"' color='"+W+"'><![CDATA["+j[Z].innerHTML+"]]></body>"}b+="</event>"}}}return b}function K(){var T="</data>";return T}var D=(new Date()).valueOf();var R=document.createElement("div");R.style.display="none";document.body.appendChild(R);R.innerHTML='<form id="'+D+'" method="post" target="_blank" action="'+C+'" accept-charset="utf-8" enctype="text/html"><input type="hidden" name="mycoolxmlbody"/> </form>';document.getElementById(D).firstChild.value=S(J).replace("\u2013","-")+B()+K();document.getElementById(D).submit();R.parentNode.removeChild(R);grid=null};
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.toPDF=function(x,f,m,n){function g(c){return c.replace(html_regexp,"")}function j(c){c=parseFloat(c);return isNaN(c)?"auto":100*c/(o+1)}function t(c){c=parseFloat(c);return isNaN(c)?"auto":100*c/k}function q(c){var a="";if(scheduler.matrix&&scheduler.matrix[scheduler._mode])c=c[0].childNodes;for(var b=0;b<c.length;b++)a+="\n<column><![CDATA["+g(c[b].innerHTML)+"]]\></column>";o=c[0].offsetWidth;return a}function y(c,a){for(var b=parseInt(c.style.left),d=0;d<scheduler._cols.length;d++)if(b-=
|
||||
scheduler._cols[d],b<0)return d;return a}function z(c,a){for(var b=parseInt(c.style.top),d=0;d<scheduler._colsS.heights.length;d++)if(scheduler._colsS.heights[d]>b)return d;return a}function w(c){for(var a="",b=c.firstChild.rows,d=0;d<b.length;d++){for(var e=[],h=0;h<b[d].cells.length;h++)e.push(b[d].cells[h].firstChild.innerHTML);a+="\n<row height='"+c.firstChild.rows[d].cells[0].offsetHeight+"'><![CDATA["+g(e.join("|"))+"]]\></row>";k=c.firstChild.rows[0].cells[0].offsetHeight}return a}function A(c){var a=
|
||||
"<data profile='"+c+"'";m&&(a+=" header='"+m+"'");n&&(a+=" footer='"+n+"'");a+=">";a+="<scale mode='"+scheduler._mode+"' today='"+scheduler._els.dhx_cal_date[0].innerHTML+"'>";if(scheduler._mode=="agenda"){var b=scheduler._els.dhx_cal_header[0].childNodes[0].childNodes;a+="<column>"+g(b[0].innerHTML)+"</column><column>"+g(b[1].innerHTML)+"</column>"}else if(scheduler._mode=="year")for(var b=scheduler._els.dhx_cal_data[0].childNodes,d=0;d<b.length;d++)a+="<month label='"+g(b[d].childNodes[0].innerHTML)+
|
||||
"'>",a+=q(b[d].childNodes[1].childNodes),a+=w(b[d].childNodes[2]),a+="</month>";else{a+="<x>";b=scheduler._els.dhx_cal_header[0].childNodes;a+=q(b);a+="</x>";var e=scheduler._els.dhx_cal_data[0];if(scheduler.matrix&&scheduler.matrix[scheduler._mode]){a+="<y>";for(d=0;d<e.firstChild.rows.length;d++)a+="<row><![CDATA["+e.firstChild.rows[d].cells[0].innerHTML+"]]\></row>";a+="</y>";k=e.firstChild.rows[0].cells[0].offsetHeight}else if(e.firstChild.tagName=="TABLE")a+=w(e);else{for(e=e.childNodes[e.childNodes.length-
|
||||
1];e.className.indexOf("dhx_scale_holder")==-1;)e=e.previousSibling;e=e.childNodes;a+="<y>";for(d=0;d<e.length;d++)a+="\n<row><![CDATA["+g(e[d].innerHTML)+"]]\></row>";a+="</y>";k=e[0].offsetHeight}}a+="</scale>";return a}function r(c,a){return(window.getComputedStyle?window.getComputedStyle(c,null)[a]:c.currentStyle?c.currentStyle[a]:null)||""}function B(){var c="",a=scheduler._rendered;if(scheduler._mode=="agenda")for(var b=0;b<a.length;b++)c+="<event><head>"+g(a[b].childNodes[0].innerHTML)+"</head><body>"+
|
||||
g(a[b].childNodes[2].innerHTML)+"</body></event>";else if(scheduler._mode=="year"){a=scheduler.get_visible_events();for(b=0;b<a.length;b++){var d=a[b].start_date;if(d.valueOf()<scheduler._min_date.valueOf())d=scheduler._min_date;for(;d<a[b].end_date;){var e=d.getMonth()+12*(d.getFullYear()-scheduler._min_date.getFullYear())-scheduler.week_starts._month,h=scheduler.week_starts[e]+d.getDate()-1;c+="<event day='"+h%7+"' week='"+Math.floor(h/7)+"' month='"+e+"'></event>";d=scheduler.date.add(d,1,"day");
|
||||
if(d.valueOf()>=scheduler._max_date.valueOf())break}}}else for(b=0;b<a.length;b++){var f=j(a[b].style.left),i=j(a[b].style.width),l=t(a[b].style.top),m=t(a[b].style.height),n=a[b].className.split(" ")[0].replace("dhx_cal_",""),o=scheduler.getEvent(a[b].getAttribute("event_id")),h=o._sday,s=o._sweek;if(scheduler._mode!="month"){if(scheduler.matrix&&scheduler.matrix[scheduler._mode])h=0,s=a[b].parentNode.parentNode.parentNode.rowIndex,i+=j(10);else{i+=j(i*20/100);f-=j(20-f*20/100);if(a[b].parentNode==
|
||||
scheduler._els.dhx_cal_data[0])continue;f+=j(a[b].parentNode.style.left);f-=j(51)}if(scheduler._mode=="timeline"){var q=k;k=180;l=t(a[b].style.top);k=q}}else m=parseInt(a[b].offsetHeight),l=parseInt(a[b].style.top)-22,h=y(a[b],h),s=z(a[b],s);c+="\n<event week='"+s+"' day='"+h+"' type='"+n+"' x='"+f+"' y='"+l+"' width='"+i+"' height='"+m+"'>";if(n=="event"){c+="<header><![CDATA["+g(a[b].childNodes[1].innerHTML)+"]]\></header>";var u=p?r(a[b].childNodes[2],"color"):"",v=p?r(a[b].childNodes[2],"backgroundColor"):
|
||||
"";c+="<body backgroundColor='"+v+"' color='"+u+"'><![CDATA["+g(a[b].childNodes[2].innerHTML)+"]]\></body>"}else u=p?r(a[b],"color"):"",v=p?r(a[b],"backgroundColor"):"",c+="<body backgroundColor='"+v+"' color='"+u+"'><![CDATA["+g(a[b].innerHTML)+"]]\></body>";c+="</event>"}return c}function C(){var c="</data>";return c}var o=0,k=0,p=!1;f=="fullcolor"&&(p=!0,f="color");f=f||"color";html_regexp=RegExp("<[^>]*>","g");var l=(new Date).valueOf(),i=document.createElement("div");i.style.display="none";document.body.appendChild(i);
|
||||
i.innerHTML='<form id="'+l+'" method="post" target="_blank" action="'+x+'" accept-charset="utf-8" enctype="application/x-www-form-urlencoded"><input type="hidden" name="mycoolxmlbody"/> </form>';document.getElementById(l).firstChild.value=A(f).replace("\u2013","-")+B()+C();document.getElementById(l).submit();i.parentNode.removeChild(i);grid=null};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){scheduler.attachEvent("onBeforeLightbox",function(F){if(this.config.readonly_form||this.getEvent(F).readonly){this.config.readonly_active=true}else{this.config.readonly_active=false;return true}for(var E=0;E<this.config.lightbox.sections.length;E++){this.config.lightbox.sections[E].focus=false}return true});function D(E,K,L,J){var G=K.getElementsByTagName(E);var F=L.getElementsByTagName(E);for(var I=F.length-1;I>=0;I--){var L=F[I];if(!J){L.disabled=true}else{var H=document.createElement("SPAN");H.className="dhx_text_disabled";H.innerHTML=J(G[I]);L.parentNode.insertBefore(H,L);L.parentNode.removeChild(L)}}}var B=scheduler._fill_lightbox;scheduler._fill_lightbox=function(){var H=this.config.lightbox.sections;if(this.config.readonly_active){for(var F=0;F<H.length;F++){if(H[F].type=="recurring"){var G=document.getElementById(H[F].id);G.style.display=G.nextSibling.style.display="none";H.splice(F,1);F--}}}var E=B.apply(this,arguments);if(this.config.readonly_active){var I=this._get_lightbox();var J=this._lightbox_r=I.cloneNode(true);D("textarea",I,J,function(K){return K.value});D("input",I,J,false);D("select",I,J,function(K){return K.options[Math.max((K.selectedIndex||0),0)].text});J.removeChild(J.childNodes[2]);J.removeChild(J.childNodes[3]);I.parentNode.insertBefore(J,I);A.call(this,J);this._lightbox=J;this.setLightboxSize();this._lightbox=null;J.onclick=function(K){var L=K?K.target:event.srcElement;if(!L.className){L=L.previousSibling}if(L&&L.className){switch(L.className){case"dhx_cancel_btn":scheduler.callEvent("onEventCancel",[scheduler._lightbox_id]);scheduler._edit_stop_event(scheduler.getEvent(scheduler._lightbox_id),false);scheduler.hide_lightbox();break}}}}return E};var A=scheduler.showCover;scheduler.showCover=function(){if(!this.config.readonly_active){A.apply(this,arguments)}};var C=scheduler.hide_lightbox;scheduler.hide_lightbox=function(){if(this._lightbox_r){this._lightbox_r.parentNode.removeChild(this._lightbox_r);this._lightbox_r=null}return C.apply(this,arguments)}});
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){function h(d,b,c,f){for(var e=b.getElementsByTagName(d),a=c.getElementsByTagName(d),g=a.length-1;g>=0;g--)if(c=a[g],f){var i=document.createElement("SPAN");i.className="dhx_text_disabled";i.innerHTML=f(e[g]);c.parentNode.insertBefore(i,c);c.parentNode.removeChild(c)}else c.disabled=!0}scheduler.attachEvent("onBeforeLightbox",function(d){if(this.config.readonly_form||this.getEvent(d).readonly)this.config.readonly_active=!0;else return this.config.readonly_active=
|
||||
!1,!0;for(var b=0;b<this.config.lightbox.sections.length;b++)this.config.lightbox.sections[b].focus=!1;return!0});var k=scheduler._fill_lightbox;scheduler._fill_lightbox=function(){var d=this.config.lightbox.sections;if(this.config.readonly_active)for(var b=0;b<d.length;b++)if(d[b].type=="recurring"){var c=document.getElementById(d[b].id);c.style.display=c.nextSibling.style.display="none";d.splice(b,1);b--}var f=k.apply(this,arguments);if(this.config.readonly_active){var e=this._get_lightbox(),a=
|
||||
this._lightbox_r=e.cloneNode(!0);a.id=scheduler.uid();a.style.color="red";h("textarea",e,a,function(a){return a.value});h("input",e,a,!1);h("select",e,a,function(a){return a.options[Math.max(a.selectedIndex||0,0)].text});a.removeChild(a.childNodes[2]);a.removeChild(a.childNodes[3]);e.parentNode.insertBefore(a,e);j.call(this,a);scheduler._lightbox&&scheduler._lightbox.parentNode.removeChild(scheduler._lightbox);this._lightbox=a;this.setLightboxSize();this._lightbox=null;a.onclick=function(a){var b=
|
||||
a?a.target:event.srcElement;if(!b.className)b=b.previousSibling;if(b&&b.className)switch(b.className){case "dhx_cancel_btn":scheduler.callEvent("onEventCancel",[scheduler._lightbox_id]),scheduler._edit_stop_event(scheduler.getEvent(scheduler._lightbox_id),!1),scheduler.hide_lightbox()}}}return f};var j=scheduler.showCover;scheduler.showCover=function(){this.config.readonly_active||j.apply(this,arguments)};var l=scheduler.hide_lightbox;scheduler.hide_lightbox=function(){if(this._lightbox_r)this._lightbox_r.parentNode.removeChild(this._lightbox_r),
|
||||
this._lightbox_r=null;return l.apply(this,arguments)}});
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
div input.radio{margin:-4px 0 0 -4px!ie;}div input.checkbox{margin:0 0 0 -4px!ie;}.dhx_form_repeat,.dhx_form_repeat input{padding:0;margin:0;font-family:Tahoma,Verdana;font-size:11px;line-height:24px;}.dhx_form_repeat{overflow:hidden;height:0;background-color:#FFF4B5;}.dhx_repeat_center,.dhx_repeat_left{height:115px;padding:10px 0 10px 10px;float:left;}.dhx_repeat_left{width:95px;}.dhx_repeat_center{width:335px;margin-top:12px;}.dhx_repeat_divider{float:left;height:115px;border-left:1px dotted #DCC43E;width:1px;}.dhx_repeat_right{float:right;height:115px;width:160px;padding:10px 3px 10px 10px;margin-top:7px;}input.dhx_repeat_text{height:16px;width:27px;margin:0 4px 0 4px;line-height:18px;padding:0 0 0 2px;}.dhx_form_repeat select{height:20px;width:87px;padding:0 0 0 2px;margin:0 4px 0 4px;}input.dhx_repeat_date{height:18px;width:80px;padding:0 0 0 2px;margin:0 4px 0 4px;background-repeat:no-repeat;background-position:64px 0;border:1px #7f9db9 solid;line-height:18px;}input.dhx_repeat_radio{margin-right:4px;}input.dhx_repeat_checkbox{margin:4px 4px 0 0;}.dhx_repeat_days td{padding-right:5px;}.dhx_repeat_days label{font-size:10px;}.dhx_custom_button_recurring{background-image:url(../imgs/but_repeat.gif);background-position:-5px 20px;width:20px;margin-right:10px;}.dhx_custom_button{width:90px;}.dhx_cal_light{width:640px;}.dhx_cal_larea{width:632px;}
|
|
@ -1,9 +1,8 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.data_attributes=function(){var C=[];var E=scheduler.templates.xml_format;for(var A in this._events){var D=this._events[A];for(var B in D){if(B.substr(0,1)!="_"){C.push([B,((B=="start_date"||B=="end_date")?E:null)])}}break}return C};scheduler.toXML=function(F){var C=[];var B=this.data_attributes();for(var A in this._events){var E=this._events[A];if(E.id.toString().indexOf("#")!=-1){continue}C.push("<event>");for(var D=0;D<B.length;D++){C.push("<"+B[D][0]+"><![CDATA["+(B[D][1]?B[D][1](E[B[D][0]]):E[B[D][0]])+"]]></"+B[D][0]+">")}C.push("</event>")}return(F||"")+"<data>"+C.join("\n")+"</data>"};scheduler.toJSON=function(){var E=[];var C=this.data_attributes();for(var B in this._events){var F=this._events[B];if(F.id.toString().indexOf("#")!=-1){continue}var F=this._events[B];var A=[];for(var D=0;D<C.length;D++){A.push(" "+C[D][0]+':"'+((C[D][1]?C[D][1](F[C[D][0]]):F[C[D][0]])||"").toString().replace(/\n/g,"")+'" ')}E.push("{"+A.join(",")+"}")}return"["+E.join(",\n")+"]"};scheduler.toICal=function(G){var F="BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//dhtmlXScheduler//NONSGML v2.2//EN\nDESCRIPTION:";var C="END:VCALENDAR";var E=scheduler.date.date_to_str("%Y%m%dT%H%i%s");var B=[];for(var A in this._events){var D=this._events[A];if(D.id.toString().indexOf("#")!=-1){continue}B.push("BEGIN:VEVENT");B.push("DTSTART:"+E(D.start_date));B.push("DTEND:"+E(D.end_date));B.push("SUMMARY:"+D.text);B.push("END:VEVENT")}return F+(G||"")+"\n"+B.join("\n")+"\n"+C};
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.data_attributes=function(){var f=[],d=scheduler.templates.xml_format,c;for(c in this._events){var e=this._events[c],a;for(a in e)a.substr(0,1)!="_"&&f.push([a,a=="start_date"||a=="end_date"?d:null]);break}return f};
|
||||
scheduler.toXML=function(f){var d=[],c=this.data_attributes(),e;for(e in this._events){var a=this._events[e];if(a.id.toString().indexOf("#")==-1){d.push("<event>");for(var b=0;b<c.length;b++)d.push("<"+c[b][0]+"><![CDATA["+(c[b][1]?c[b][1](a[c[b][0]]):a[c[b][0]])+"]]\></"+c[b][0]+">");d.push("</event>")}}return(f||"")+"<data>"+d.join("\n")+"</data>"};
|
||||
scheduler.toJSON=function(){var f=[],d=this.data_attributes(),c;for(c in this._events){var e=this._events[c];if(e.id.toString().indexOf("#")==-1){for(var e=this._events[c],a=[],b=0;b<d.length;b++)a.push(" "+d[b][0]+':"'+((d[b][1]?d[b][1](e[d[b][0]]):e[d[b][0]])||"").toString().replace(/\n/g,"")+'" ');f.push("{"+a.join(",")+"}")}}return"["+f.join(",\n")+"]"};
|
||||
scheduler.toICal=function(f){var d="BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//dhtmlXScheduler//NONSGML v2.2//EN\nDESCRIPTION:",c="END:VCALENDAR",e=scheduler.date.date_to_str("%Y%m%dT%H%i%s"),a=[],b;for(b in this._events){var g=this._events[b];g.id.toString().indexOf("#")==-1&&(a.push("BEGIN:VEVENT"),a.push("DTSTART:"+e(g.start_date)),a.push("DTEND:"+e(g.end_date)),a.push("SUMMARY:"+g.text),a.push("END:VEVENT"))}return d+(f||"")+"\n"+a.join("\n")+"\n"+c};
|
||||
|
|
|
@ -1 +1,11 @@
|
|||
window.dhtmlXTooltip={version:0.1};dhtmlXTooltip.config={className:"dhtmlXTooltip tooltip",timeout_to_display:50,delta_x:15,delta_y:-20};dhtmlXTooltip.tooltip=document.createElement("div");dhtmlXTooltip.tooltip.className=dhtmlXTooltip.config.className;dhtmlXTooltip.show=function(D,G){dhtmlXTooltip.tooltip.className=dhtmlXTooltip.config.className;var H=this.position(D);var E=D.target||D.srcElement;if(this.isTooltip(E)){return }var C=H.x+dhtmlXTooltip.config.delta_x||0;var B=H.y-dhtmlXTooltip.config.delta_y||0;this.tooltip.style.visibility="hidden";if(this.tooltip.style.removeAttribute){this.tooltip.style.removeAttribute("right");this.tooltip.style.removeAttribute("bottom")}else{this.tooltip.style.removeProperty("right");this.tooltip.style.removeProperty("bottom")}this.tooltip.style.left="0px";this.tooltip.style.top="0px";this.tooltip.innerHTML=G;scheduler._obj.appendChild(this.tooltip);var A=this.tooltip.offsetWidth;var F=this.tooltip.offsetHeight;if(document.body.offsetWidth-C-A<0){if(this.tooltip.style.removeAttribute){this.tooltip.style.removeAttribute("left")}else{this.tooltip.style.removeProperty("left")}this.tooltip.style.right=(document.body.offsetWidth-C+2*dhtmlXTooltip.config.delta_x||0)+"px"}else{if(C<0){this.tooltip.style.left=(H.x+Math.abs(dhtmlXTooltip.config.delta_x||0))+"px"}else{this.tooltip.style.left=C+"px"}}if(document.body.offsetHeight-B-F<0){if(this.tooltip.style.removeAttribute){this.tooltip.style.removeAttribute("top")}else{this.tooltip.style.removeProperty("top")}this.tooltip.style.bottom=(document.body.offsetHeight-B-2*dhtmlXTooltip.config.delta_y||0)+"px"}else{if(B<0){this.tooltip.style.top=(H.y+Math.abs(dhtmlXTooltip.config.delta_y||0))+"px"}else{this.tooltip.style.top=B+"px"}}this.tooltip.style.visibility="visible"};dhtmlXTooltip.hide=function(){if(this.tooltip.parentNode){this.tooltip.parentNode.removeChild(this.tooltip)}};dhtmlXTooltip.delay=function(D,B,C,A){if(this.tooltip._timeout_id){window.clearTimeout(this.tooltip._timeout_id)}this.tooltip._timeout_id=setTimeout(function(){var E=D.apply(B,C);D=obj=C=null;return E},A||this.config.timeout_to_display)};dhtmlXTooltip.isTooltip=function(B){var A=false;while(B&&!A){A=(B.className==this.tooltip.className);B=B.parentNode}return A};dhtmlXTooltip.position=function(A){var A=A||window.event;if(A.pageX||A.pageY){return{x:A.pageX,y:A.pageY}}var B=((dhtmlx._isIE)&&(document.compatMode!="BackCompat"))?document.documentElement:document.body;return{x:A.clientX+B.scrollLeft-B.clientLeft,y:A.clientY+B.scrollTop-B.clientTop}};scheduler.attachEvent("onMouseMove",function(D,F){var C=F||window.event;var E=C.target||C.srcElement;if(D||dhtmlXTooltip.isTooltip(E)){var B=scheduler.getEvent(D)||scheduler.getEvent(dhtmlXTooltip.tooltip.event_id);dhtmlXTooltip.tooltip.event_id=B.id;var G=scheduler.templates.tooltip_text(B.start_date,B.end_date,B);if(_isIE){var A=document.createEventObject(C)}dhtmlXTooltip.delay(dhtmlXTooltip.show,dhtmlXTooltip,[A||C,G])}else{dhtmlXTooltip.delay(dhtmlXTooltip.hide,dhtmlXTooltip,[])}});scheduler.templates.tooltip_text=function(C,A,B){return"<b>Event:</b> "+B.text+"<br/><b>Start date:</b> "+scheduler.templates.tooltip_date_format(C)+"<br/><b>End date:</b> "+scheduler.templates.tooltip_date_format(A)};
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
window.dhtmlXTooltip={};dhtmlXTooltip.config={className:"dhtmlXTooltip tooltip",timeout_to_display:50,delta_x:15,delta_y:-20};dhtmlXTooltip.tooltip=document.createElement("div");dhtmlXTooltip.tooltip.className=dhtmlXTooltip.config.className;
|
||||
dhtmlXTooltip.show=function(b,d){var c=dhtmlXTooltip,f=this.tooltip,a=f.style;c.tooltip.className=c.config.className;var e=this.position(b),k=b.target||b.srcElement;if(!this.isTooltip(k)){var g=0,l=0,h=scheduler._obj;if(h.offsetParent){do g+=h.offsetLeft,l+=h.offsetTop;while(h=h.offsetParent)}var i=e.x+(c.config.delta_x||0)-g,j=e.y-(c.config.delta_y||0)-l;a.visibility="hidden";a.removeAttribute?(a.removeAttribute("right"),a.removeAttribute("bottom")):(a.removeProperty("right"),a.removeProperty("bottom"));
|
||||
a.left="0";a.top="0";this.tooltip.innerHTML=d;scheduler._obj.appendChild(this.tooltip);var m=this.tooltip.offsetWidth,n=this.tooltip.offsetHeight;scheduler._obj.offsetWidth-i-(scheduler.xy.margin_left||0)-m<0?(a.removeAttribute?a.removeAttribute("left"):a.removeProperty("left"),a.right=scheduler._obj.offsetWidth-i+2*(c.config.delta_x||0)+"px"):a.left=i<0?e.x+Math.abs(c.config.delta_x||0)+"px":i+"px";scheduler._obj.offsetHeight-j-(scheduler.xy.margin_top||0)-n<0?(a.removeAttribute?a.removeAttribute("top"):
|
||||
a.removeProperty("top"),a.bottom=scheduler._obj.offsetHeight-j-2*(c.config.delta_y||0)+"px"):a.top=j<0?e.y+Math.abs(c.config.delta_y||0)+"px":j+"px";a.visibility="visible"}};dhtmlXTooltip.hide=function(){this.tooltip.parentNode&&this.tooltip.parentNode.removeChild(this.tooltip)};dhtmlXTooltip.delay=function(b,d,c,f){this.tooltip._timeout_id&&window.clearTimeout(this.tooltip._timeout_id);this.tooltip._timeout_id=setTimeout(function(){var a=b.apply(d,c);b=d=c=null;return a},f||this.config.timeout_to_display)};
|
||||
dhtmlXTooltip.isTooltip=function(b){for(var d=!1;b&&!d;)d=b.className==this.tooltip.className,b=b.parentNode;return d};dhtmlXTooltip.position=function(b){b=b||window.event;if(b.pageX||b.pageY)return{x:b.pageX,y:b.pageY};var d=dhtmlx._isIE&&document.compatMode!="BackCompat"?document.documentElement:document.body;return{x:b.clientX+d.scrollLeft-d.clientLeft,y:b.clientY+d.scrollTop-d.clientTop}};
|
||||
scheduler.attachEvent("onMouseMove",function(b,d){var c=window.event||d,f=c.target||c.srcElement,a=dhtmlXTooltip;if(b||a.isTooltip(f)){var e=scheduler.getEvent(b)||scheduler.getEvent(a.tooltip.event_id);if(e){a.tooltip.event_id=e.id;var k=scheduler.templates.tooltip_text(e.start_date,e.end_date,e),g=void 0;_isIE&&(g=document.createEventObject(c));a.delay(a.show,a,[g||c,k])}}else a.delay(a.hide,a,[])});scheduler.attachEvent("onBeforeDrag",function(){dhtmlXTooltip.hide();return!0});
|
||||
scheduler.templates.tooltip_date_format=scheduler.date.date_to_str("%Y-%m-%d %H:%i");scheduler.templates.tooltip_text=function(b,d,c){return"<b>Event:</b> "+c.text+"<br/><b>Start date:</b> "+scheduler.templates.tooltip_date_format(b)+"<br/><b>End date:</b> "+scheduler.templates.tooltip_date_format(d)};
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
.dhx_cal_prev_button,.dhx_cal_next_button,.dhx_cal_today_button,.dhx_cal_add_button{top:6px!important;left:10px;border:1px solid #575D65;border-top:1px solid #4E5052;color:#FFF;text-shadow:0 -1px 0 #65696E;background-image:-webkit-gradient(linear,left top,left bottom,from(#B2B6BC),to(#6B737E));background-color:#989B9F;background-position:0 1px;background-repeat:repeat-x;-webkit-border-radius:5px;padding:3px;text-align:center;text-decoration:none;}.dhx_cal_today_button{left:55px;}.dhx_cal_next_button{left:146px;}.dhx_cal_add_button{right:9px;left:auto;width:20px;font-size:20px;padding:1px 2px 2px 2px;}.dhx_cal_navline .dhx_cal_date{top:7px;left:160px;right:350px;padding-top:4px;width:auto;text-align:center;color:#4F5459;}.dhx_cal_navline{background:-webkit-gradient(linear,0% 0,0% 100%,color-stop(0,#F4F5F8),color-stop(0.3,#F1F2F4),color-stop(0.7,#C4C7D0),color-stop(1,#A6AAB7));border-bottom:1px solid #797F90;height:40px!important;font-family:Helvetica;font-weight:bold;font-size:13px;}.dhx_cal_tab{top:6px!important;color:#4F5459;text-align:center;padding:5px 10px;width:80px;background-image:-webkit-gradient(linear,0% 0,0% 100%,from(#F7F7F7),to(#B9BDC7));background-color:#CFD0D1;background-position:0 1px;background-repeat:repeat-x;text-decoration:none;border:1px solid #95989F;border-top:1px solid #686A6A;height:16px;}.dhx_cal_tab.active{background-image:-webkit-gradient(linear,0% 0,0% 100%,from(#B0B2B6),to(#666D74));background-color:#949799;background-position:0 1px;background-repeat:repeat-x;border:1px solid #4C4D4F;border-top:1px solid #52585C;color:#F8F8F8;text-shadow:0 -1px 0 #5E6063;text-decoration:none;height:16px;padding:5px 10px;z-index:100;}.dhx_cal_light{-webkit-transition:-webkit-transform;-webkit-transform-style:preserve-3d;}.dhx_cal_cover{opacity:.5;}.dhx_cal_ltext{padding-top:0;padding-bottom:0;}.dhx_cal_ltext textarea{-webkit-background-size:0;-webkit-border-radius:0;height:94%;}.dhx_mini_calendar .dhx_month_head{height:35px;line-height:35px;text-align:center;padding-right:0;padding-left:0;}.dhx_mini_calendar .dhx_year_month{height:35px;line-height:30px;background:-webkit-gradient(linear,0% 0,0% 100%,from(#F4F5F8),to(#8A8E9A));font-family:Helvetica;font-weight:bold;font-size:13px;}.dhx_mini_calendar .dhx_year_month .dhx_cal_prev_button,.dhx_mini_calendar .dhx_year_month .dhx_cal_next_button{line-height:normal;}
|
|
@ -1,9 +1,16 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler._props={};scheduler.createUnitsView=function(A,E,D,B,C){if(typeof A=="object"){D=A.list;E=A.property;B=A.size||0;C=A.step||1;A=A.name}scheduler.date[A+"_start"]=scheduler.date.day_start;scheduler.templates[A+"_date"]=function(F){return scheduler.templates.day_date(F)};scheduler.templates[A+"_scale_date"]=function(G){if(!D.length){return""}var F=(scheduler._props[A].position||0)+Math.floor((scheduler._correct_shift(G.valueOf(),1)-scheduler._min_date.valueOf())/(60*60*24*1000));if(D[F].css){return"<span class='"+D[F].css+"'>"+D[F].label+"</span>"}else{return D[F].label}};scheduler.date["add_"+A]=function(F,G){return scheduler.date.add(F,G,"day")};scheduler.date["get_"+A+"_end"]=function(F){return scheduler.date.add(F,B||D.length,"day")};scheduler._props[A]={map_to:E,options:D,size:B,step:C,position:0};scheduler.attachEvent("onOptionsLoad",function(){var F=scheduler._props[A].order={};for(var G=0;G<D.length;G++){F[D[G].key]=G}if(scheduler._date){scheduler.setCurrentView(scheduler._date,scheduler._mode)}});scheduler.callEvent("onOptionsLoad",[])};scheduler.scrollUnit=function(A){var B=scheduler._props[this._mode];if(B){B.position=Math.min(Math.max(0,B.position+A),B.options.length-B.size);this.update_view()}};(function(){var D=function(L,J){if(L&&typeof L.order[J[L.map_to]]=="undefined"){var I=scheduler;var H=24*60*60*1000;var K=Math.floor((J.end_date-I._min_date)/H);J[L.map_to]=L.options[Math.min(K+L.position,L.options.length-1)].key;return true}};var B=scheduler._reset_scale;var F=scheduler.is_visible_events;scheduler.is_visible_events=function(I){var H=F.apply(this,arguments);if(H){var K=scheduler._props[this._mode];if(K&&K.size){var J=K.order[I[K.map_to]];if(J<K.position||J>=K.size+K.position){return false}}}return H};scheduler._reset_scale=function(){var M=scheduler._props[this._mode];var H=B.apply(this,arguments);if(M){this._max_date=this.date.add(this._min_date,1,"day");var L=this._els.dhx_cal_data[0].childNodes;for(var I=0;I<L.length;I++){L[I].className=L[I].className.replace("_now","")}if(M.size&&M.size<M.options.length){var J=this._els.dhx_cal_header[0];var K=document.createElement("DIV");if(M.position){K.className="dhx_cal_prev_button";K.style.cssText="left:1px;top:2px;position:absolute;";K.innerHTML=" ";J.firstChild.appendChild(K);K.onclick=function(){scheduler.scrollUnit(M.step*-1)}}if(M.position+M.size<M.options.length){K=document.createElement("DIV");K.className="dhx_cal_next_button";K.style.cssText="left:auto; right:0px;top:2px;position:absolute;";K.innerHTML=" ";J.lastChild.appendChild(K);K.onclick=function(){scheduler.scrollUnit(M.step)}}}}return H};var C=scheduler._get_event_sday;scheduler._get_event_sday=function(H){var I=scheduler._props[this._mode];if(I){D(I,H);return I.order[H[I.map_to]]-I.position}return C.call(this,H)};var A=scheduler.locate_holder_day;scheduler.locate_holder_day=function(I,H,J){var K=scheduler._props[this._mode];if(K){D(K,J);return K.order[J[K.map_to]]*1+(H?1:0)-K.position}return A.apply(this,arguments)};var E=scheduler._mouse_coords;scheduler._mouse_coords=function(){var K=scheduler._props[this._mode];var J=E.apply(this,arguments);if(K){var H=this._drag_event;if(this._drag_id){H=this.getEvent(this._drag_id);this._drag_event._dhx_changed=true}var I=Math.min(J.x+K.position,K.options.length-1);H[K.map_to]=K.options[I].key;J.x=I/10000000}return J};var G=scheduler._time_order;scheduler._time_order=function(H){var I=scheduler._props[this._mode];if(I){H.sort(function(K,J){return I.order[K[I.map_to]]>I.order[J[I.map_to]]?1:-1})}else{G.apply(this,arguments)}};scheduler.attachEvent("onEventAdded",function(K,I){if(this._loading){return true}for(var H in scheduler._props){var J=scheduler._props[H];if(typeof I[J.map_to]=="undefined"){I[J.map_to]=J.options[0].key}}return true});scheduler.attachEvent("onEventCreated",function(K,H){var J=scheduler._props[this._mode];if(J){var I=this.getEvent(K);this._mouse_coords(H);D(J,I);this.event_updated(I)}return true})})();
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler._props={};
|
||||
scheduler.createUnitsView=function(a,f,j,g,k,l){if(typeof a=="object")j=a.list,f=a.property,g=a.size||0,k=a.step||1,l=a.skip_incorrect,a=a.name;scheduler._props[a]={map_to:f,options:j,step:k,position:0};if(g>scheduler._props[a].options.length)scheduler._props[a]._original_size=g,g=0;scheduler._props[a].size=g;scheduler._props[a].skip_incorrect=l||!1;scheduler.date[a+"_start"]=scheduler.date.day_start;scheduler.templates[a+"_date"]=function(a){return scheduler.templates.day_date(a)};scheduler.templates[a+
|
||||
"_scale_date"]=function(c){var h=scheduler._props[a].options;if(!h.length)return"";var f=(scheduler._props[a].position||0)+Math.floor((scheduler._correct_shift(c.valueOf(),1)-scheduler._min_date.valueOf())/864E5);return h[f].css?"<span class='"+h[f].css+"'>"+h[f].label+"</span>":h[f].label};scheduler.date["add_"+a]=function(a,f){return scheduler.date.add(a,f,"day")};scheduler.date["get_"+a+"_end"]=function(c){return scheduler.date.add(c,scheduler._props[a].size||scheduler._props[a].options.length,
|
||||
"day")};scheduler.attachEvent("onOptionsLoad",function(){for(var c=scheduler._props[a],f=c.order={},g=c.options,i=0;i<g.length;i++)f[g[i].key]=i;if(c._original_size&&c.size==0)c.size=c._original_size,delete c.original_size;c.size>g.length?(c._original_size=c.size,c.size=0):c.size=c._original_size||c.size;scheduler._date&&scheduler._mode==a&&scheduler.setCurrentView(scheduler._date,scheduler._mode)});scheduler.callEvent("onOptionsLoad",[])};
|
||||
scheduler.scrollUnit=function(a){var f=scheduler._props[this._mode];if(f)f.position=Math.min(Math.max(0,f.position+a),f.options.length-f.size),this.update_view()};
|
||||
(function(){var a=function(b){var d=scheduler._props[scheduler._mode];if(d&&d.order&&d.skip_incorrect){for(var a=[],e=0;e<b.length;e++)typeof d.order[b[e][d.map_to]]!="undefined"&&a.push(b[e]);b.splice(0,b.length);b.push.apply(b,a)}return b},f=scheduler._pre_render_events_table;scheduler._pre_render_events_table=function(b,d){b=a(b);return f.apply(this,[b,d])};var j=scheduler._pre_render_events_line;scheduler._pre_render_events_line=function(b,d){b=a(b);return j.apply(this,[b,d])};var g=function(b,
|
||||
d){if(b&&typeof b.order[d[b.map_to]]=="undefined"){var a=scheduler,e=864E5,c=Math.floor((d.end_date-a._min_date)/e);d[b.map_to]=b.options[Math.min(c+b.position,b.options.length-1)].key;return!0}},k=scheduler._reset_scale,l=scheduler.is_visible_events;scheduler.is_visible_events=function(b){var d=l.apply(this,arguments);if(d){var a=scheduler._props[this._mode];if(a&&a.size){var e=a.order[b[a.map_to]];if(e<a.position||e>=a.size+a.position)return!1}}return d};scheduler._reset_scale=function(){var b=
|
||||
scheduler._props[this._mode],a=k.apply(this,arguments);if(b){this._max_date=this.date.add(this._min_date,1,"day");for(var c=this._els.dhx_cal_data[0].childNodes,e=0;e<c.length;e++)c[e].className=c[e].className.replace("_now","");if(b.size&&b.size<b.options.length){var f=this._els.dhx_cal_header[0],g=document.createElement("DIV");if(b.position)g.className="dhx_cal_prev_button",g.style.cssText="left:1px;top:2px;position:absolute;",g.innerHTML=" ",f.firstChild.appendChild(g),g.onclick=function(){scheduler.scrollUnit(b.step*
|
||||
-1)};if(b.position+b.size<b.options.length)g=document.createElement("DIV"),g.className="dhx_cal_next_button",g.style.cssText="left:auto; right:0px;top:2px;position:absolute;",g.innerHTML=" ",f.lastChild.appendChild(g),g.onclick=function(){scheduler.scrollUnit(b.step)}}}return a};var c=scheduler._get_event_sday;scheduler._get_event_sday=function(b){var a=scheduler._props[this._mode];return a?(g(a,b),a.order[b[a.map_to]]-a.position):c.call(this,b)};var h=scheduler.locate_holder_day;scheduler.locate_holder_day=
|
||||
function(a,d,c){var e=scheduler._props[this._mode];return e?(g(e,c),e.order[c[e.map_to]]*1+(d?1:0)-e.position):h.apply(this,arguments)};var m=scheduler._mouse_coords;scheduler._mouse_coords=function(){var a=scheduler._props[this._mode],d=m.apply(this,arguments);if(a){if(!this._drag_event)this._drag_event={};var c=this._drag_event;if(this._drag_id&&this._drag_mode)c=this.getEvent(this._drag_id),this._drag_event._dhx_changed=!0;var e=Math.min(d.x+a.position,a.options.length-1);c[a.map_to]=a.options[e].key;
|
||||
d.x=0;d.custom=!0}return d};var i=scheduler._time_order;scheduler._time_order=function(a){var d=scheduler._props[this._mode];d?a.sort(function(a,b){return d.order[a[d.map_to]]>d.order[b[d.map_to]]?1:-1}):i.apply(this,arguments)};scheduler.attachEvent("onEventAdded",function(a,d){if(this._loading)return!0;for(var c in scheduler._props){var e=scheduler._props[c];if(typeof d[e.map_to]=="undefined")d[e.map_to]=e.options[0].key}return!0});scheduler.attachEvent("onEventCreated",function(a,c){var f=scheduler._props[this._mode];
|
||||
if(f){var e=this.getEvent(a);this._mouse_coords(c);g(f,e);this.event_updated(e)}return!0})})();
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
/*
|
||||
dhtmlxScheduler v.2.3
|
||||
|
||||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
|
||||
(c) DHTMLX Ltd.
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){var C=true;var A=scheduler.date.str_to_date("%Y-%m-%d");var B=scheduler.date.date_to_str("%Y-%m-%d");scheduler.attachEvent("onBeforeViewChange",function(K,D,F,J){if(C){C=false;var E={};var G=(document.location.hash||"").replace("#","").split(",");for(var H=0;H<G.length;H++){var M=G[H].split("=");if(M.length==2){E[M[0]]=M[1]}}if(E.date||E.mode){try{this.setCurrentView((E.date?A(E.date):null),(E.mode||null))}catch(I){this.setCurrentView((E.date?A(E.date):null),F)}return false}}var L="#date="+B(J||D)+",mode="+(F||K);document.location.hash=L;return true})});
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler.attachEvent("onTemplatesReady",function(){var d=!0,e=scheduler.date.str_to_date("%Y-%m-%d"),h=scheduler.date.date_to_str("%Y-%m-%d");scheduler.attachEvent("onBeforeViewChange",function(i,j,f,k){if(d){d=!1;for(var a={},g=(document.location.hash||"").replace("#","").split(","),b=0;b<g.length;b++){var c=g[b].split("=");c.length==2&&(a[c[0]]=c[1])}if(a.date||a.mode){try{this.setCurrentView(a.date?e(a.date):null,a.mode||null)}catch(m){this.setCurrentView(a.date?e(a.date):null,f)}return!1}}var l=
|
||||
"#date="+h(k||j)+",mode="+(f||i);document.location.hash=l;return!0})});
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License
|
||||
to use it in not GPL project. Please contact sales@dhtmlx.com for details
|
||||
*/
|
||||
scheduler._wa={};scheduler.xy.week_agenda_scale_height=20;scheduler.templates.week_agenda_event_text=function(c,e,f){return scheduler.templates.event_date(c)+" "+f.text};scheduler.date.week_agenda_start=scheduler.date.week_start;scheduler.date.week_agenda_end=function(c){return scheduler.date.add(c,7,"day")};scheduler.date.add_week_agenda=function(c,e){return scheduler.date.add(c,e*7,"day")};
|
||||
scheduler.attachEvent("onSchedulerReady",function(){var c=scheduler.templates;if(!c.week_agenda_date)c.week_agenda_date=c.week_date});(function(){var c=scheduler.date.date_to_str("%l, %F %d");scheduler.templates.week_agenda_scale_date=function(e){return c(e)}})();
|
||||
scheduler.attachEvent("onTemplatesReady",function(){scheduler.attachEvent("onSchedulerResize",function(){return this._mode=="week_agenda"?(this.week_agenda_view(!0),!1):!0});var c=scheduler.render_data;scheduler.render_data=function(b){if(this._mode=="week_agenda")f();else return c.apply(this,arguments)};var e=function(){scheduler._cols=[];var b=parseInt(scheduler._els.dhx_cal_data[0].style.width);scheduler._cols.push(Math.floor(b/2));scheduler._cols.push(b-scheduler._cols[0]-1);scheduler._colsS=
|
||||
{0:[],1:[]};for(var a=parseInt(scheduler._els.dhx_cal_data[0].style.height),m=0;m<3;m++)scheduler._colsS[0].push(Math.floor(a/(3-scheduler._colsS[0].length))),a-=scheduler._colsS[0][m];scheduler._colsS[1].push(scheduler._colsS[0][0]);scheduler._colsS[1].push(scheduler._colsS[0][1]);a=scheduler._colsS[0][scheduler._colsS[0].length-1];scheduler._colsS[1].push(Math.floor(a/2));scheduler._colsS[1].push(a-scheduler._colsS[1][scheduler._colsS[1].length-1])},f=function(){for(var b=scheduler._els.dhx_cal_data[0].innerHTML=
|
||||
"",a=0;a<2;a++){var m=scheduler._cols[a],c="dhx_wa_column";a==1&&(c+=" dhx_wa_column_last");b+="<div class='"+c+"' style='width: "+m+"px;'>";for(var h=0;h<scheduler._colsS[a].length;h++){var k=scheduler.xy.week_agenda_scale_height-2,e=scheduler._colsS[a][h]-k-2;b+="<div class='dhx_wa_day_cont'><div style='height:"+k+"px; line-height:"+k+"px;' class='dhx_wa_scale_bar'></div><div style='height:"+e+"px;' class='dhx_wa_day_data'></div></div>"}b+="</div>"}scheduler._els.dhx_cal_date[0].innerHTML=scheduler.templates[scheduler._mode+
|
||||
"_date"](scheduler._min_date,scheduler._max_date,scheduler._mode);scheduler._els.dhx_cal_data[0].innerHTML=b;for(var i=scheduler._els.dhx_cal_data[0].getElementsByTagName("div"),l=[],a=0;a<i.length;a++)i[a].className=="dhx_wa_day_cont"&&l.push(i[a]);scheduler._wa._selected_divs=[];for(var f=scheduler.get_visible_events(),j=scheduler.date.week_start(scheduler._date),n=scheduler.date.add(j,1,"day"),a=0;a<7;a++){l[a]._date=j;var s=l[a].childNodes[0],t=l[a].childNodes[1];s.innerHTML=scheduler.templates.week_agenda_scale_date(j);
|
||||
for(var o=[],q=0;q<f.length;q++){var r=f[q];r.start_date<n&&r.end_date>j&&o.push(r)}o.sort(function(a,b){return a.start_date.valueOf()==b.start_date.valueOf()?a.id>b.id?1:-1:a.start_date>b.start_date?1:-1});for(h=0;h<o.length;h++){var d=o[h],g=document.createElement("div");scheduler._rendered.push(g);g.className="dhx_wa_ev_body";if(d._text_style)g.style.cssText=d._text_style;if(d.color)g.style.backgroundColor=d.color;if(d.textColor)g.style.color=d.textColor;scheduler._select_id&&d.id==scheduler._select_id&&
|
||||
(g.className+=" dhx_cal_event_selected",scheduler._wa._selected_divs.push(g));var p="";d._timed||(p="middle",d.start_date.valueOf()>=j.valueOf()&&d.start_date.valueOf()<=n.valueOf()&&(p="start"),d.end_date.valueOf()>=j.valueOf()&&d.end_date.valueOf()<=n.valueOf()&&(p="end"));g.innerHTML=scheduler.templates.week_agenda_event_text(d.start_date,d.end_date,d,j,p);g.setAttribute("event_id",d.id);t.appendChild(g)}j=scheduler.date.add(j,1,"day");n=scheduler.date.add(n,1,"day")}};scheduler.week_agenda_view=
|
||||
function(b){scheduler._min_date=scheduler.date.week_start(scheduler._date);scheduler._max_date=scheduler.date.add(scheduler._min_date,1,"week");scheduler.set_sizes();if(b)scheduler._table_view=!0,scheduler._wa._prev_data_border=scheduler._els.dhx_cal_data[0].style.borderTop,scheduler._els.dhx_cal_data[0].style.borderTop=0,scheduler._els.dhx_cal_data[0].style.overflowY="hidden",scheduler._els.dhx_cal_date[0].innerHTML="",scheduler._els.dhx_cal_data[0].style.top=parseInt(scheduler._els.dhx_cal_data[0].style.top)-
|
||||
scheduler.xy.bar_height-1+"px",scheduler._els.dhx_cal_data[0].style.height=parseInt(scheduler._els.dhx_cal_data[0].style.height)+scheduler.xy.bar_height+1+"px",scheduler._els.dhx_cal_header[0].style.display="none",e(),f();else{scheduler._table_view=!1;if(scheduler._wa._prev_data_border)scheduler._els.dhx_cal_data[0].style.borderTop=scheduler._wa._prev_data_border;scheduler._els.dhx_cal_data[0].style.overflowY="auto";scheduler._els.dhx_cal_data[0].style.top=parseInt(scheduler._els.dhx_cal_data[0].style.top)+
|
||||
scheduler.xy.bar_height+"px";scheduler._els.dhx_cal_data[0].style.height=parseInt(scheduler._els.dhx_cal_data[0].style.height)-scheduler.xy.bar_height+"px";scheduler._els.dhx_cal_header[0].style.display="block"}};scheduler.mouse_week_agenda=function(b){for(var a=b.ev,c=a.srcElement||a.target;c.parentNode;){if(c._date)var e=c._date;c=c.parentNode}if(!e)return b;b.x=0;var h=e.valueOf()-scheduler._min_date.valueOf();b.y=Math.ceil(h/6E4/this.config.time_step);if(this._drag_mode=="move"){this._drag_event._dhx_changed=
|
||||
!0;this._select_id=this._drag_id;for(var k=0;k<scheduler._rendered.length;k++)if(scheduler._drag_id==this._rendered[k].getAttribute("event_id"))var f=this._rendered[k];if(!scheduler._wa._dnd){var i=f.cloneNode(!0);this._wa._dnd=i;i.className=f.className;i.id="dhx_wa_dnd";i.className+=" dhx_wa_dnd";document.body.appendChild(i)}var l=document.getElementById("dhx_wa_dnd");l.style.top=(a.pageY||a.clientY)+20+"px";l.style.left=(a.pageX||a.clientX)+20+"px"}return b};scheduler.attachEvent("onBeforeEventChanged",
|
||||
function(){if(this._mode=="week_agenda"&&this._drag_mode=="move"){var b=document.getElementById("dhx_wa_dnd");b.parentNode.removeChild(b);scheduler._wa._dnd=!1}return!0});scheduler.attachEvent("onEventSave",function(b,a,c){if(c)this._select_id=b;return!0});scheduler._wa._selected_divs=[];scheduler.attachEvent("onClick",function(b){if(this._mode=="week_agenda"){if(scheduler._wa._selected_divs)for(var a=0;a<this._wa._selected_divs.length;a++){var c=this._wa._selected_divs[a];c.className=c.className.replace(/ dhx_cal_event_selected/,
|
||||
"")}this.for_rendered(b,function(a){a.className+=" dhx_cal_event_selected";scheduler._wa._selected_divs.push(a)});this._select_id=b;return!1}return!0})});
|
Before Width: | Height: | Size: 180 B |
Before Width: | Height: | Size: 366 B |
After Width: | Height: | Size: 247 B |
After Width: | Height: | Size: 252 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 616 B |
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 388 B |
After Width: | Height: | Size: 452 B |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 89 B |
After Width: | Height: | Size: 89 B |
After Width: | Height: | Size: 148 B |