summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Likins <alikins@grimlock.devel.redhat.com>2008-08-26 14:51:26 -0400
committerAdrian Likins <alikins@grimlock.devel.redhat.com>2008-08-26 14:51:26 -0400
commit31f096ef3065c13945c96b815ff4feeaf1a46e11 (patch)
tree399ad8a88ecba9611f5b38b5982c3520c777139e
parent44733335dd76b59e211e8397f008abdba79a3b5f (diff)
parent41f53ee4a0edb6899b8377dabbdba525cb6d1844 (diff)
downloadfunc-31f096ef3065c13945c96b815ff4feeaf1a46e11.tar.gz
func-31f096ef3065c13945c96b815ff4feeaf1a46e11.tar.xz
func-31f096ef3065c13945c96b815ff4feeaf1a46e11.zip
Merge branch 'master' into cmd_run_env
-rw-r--r--func/minion/func_arg.py1
-rw-r--r--func/minion/modules/certmastermod.py41
-rw-r--r--func/minion/modules/command.py28
-rw-r--r--func/minion/modules/copyfile.py41
-rw-r--r--func/minion/modules/echo.py25
-rw-r--r--func/minion/modules/filetracker.py51
-rw-r--r--func/minion/modules/hardware.py26
-rw-r--r--func/minion/modules/iptables/__init__.py121
-rw-r--r--func/minion/modules/iptables/common.py2
-rw-r--r--func/minion/modules/jboss.py74
-rw-r--r--func/minion/modules/mount.py79
-rw-r--r--func/minion/modules/nagios-check.py18
-rw-r--r--func/minion/modules/netapp/common.py2
-rw-r--r--func/minion/modules/netapp/snap.py47
-rw-r--r--func/minion/modules/netapp/vol/__init__.py79
-rw-r--r--func/minion/modules/netapp/vol/clone.py45
-rw-r--r--func/minion/modules/networktest.py69
-rw-r--r--func/minion/modules/overlord.py18
-rw-r--r--func/minion/modules/process.py56
-rw-r--r--func/minion/modules/reboot.py27
-rw-r--r--func/minion/modules/rpms.py35
-rw-r--r--func/minion/modules/smart.py19
-rw-r--r--func/minion/modules/snmp.py30
-rw-r--r--func/minion/modules/sysctl.py38
-rw-r--r--func/minion/modules/test.py52
-rw-r--r--func/minion/modules/yumcmd.py33
-rwxr-xr-xfunc/overlord/client.py2
-rw-r--r--func/overlord/cmd_modules/call.py1
-rw-r--r--func/overlord/cmd_modules/copyfile.py16
-rw-r--r--func/overlord/modules/copyfile.py27
-rwxr-xr-xfuncweb/Makefile1
-rw-r--r--funcweb/etc/pam.d/funcweb3
-rw-r--r--funcweb/funcweb.spec61
-rw-r--r--funcweb/funcweb.te12
-rw-r--r--funcweb/funcweb/commands.py9
-rw-r--r--funcweb/funcweb/controllers.py330
-rw-r--r--funcweb/funcweb/identity/pam.py11
-rw-r--r--funcweb/funcweb/result_handler.py125
-rw-r--r--funcweb/funcweb/static/css/dhtmlxtree.css61
-rwxr-xr-xfuncweb/funcweb/static/css/groupscss.css207
-rw-r--r--funcweb/funcweb/static/css/style.css22
-rw-r--r--funcweb/funcweb/static/images/button_overadd.jpgbin0 -> 1876 bytes
-rw-r--r--funcweb/funcweb/static/images/buttonadd.jpgbin0 -> 1483 bytes
-rw-r--r--funcweb/funcweb/static/images/groupremovebtn.jpgbin0 -> 1322 bytes
-rw-r--r--funcweb/funcweb/static/images/groupremovebtnhover.jpgbin0 -> 1403 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/blank.gifbin0 -> 56 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/but_cut.gifbin0 -> 87 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/folderClosed.gifbin0 -> 135 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/folderOpen.gifbin0 -> 139 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/iconCheckAll.gifbin0 -> 123 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/iconCheckDis.gifbin0 -> 126 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/iconCheckGray.gifbin0 -> 126 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/iconUncheckAll.gifbin0 -> 111 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/iconUncheckDis.gifbin0 -> 117 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/leaf.gifbin0 -> 123 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line.gifbin0 -> 71 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line1.gifbin0 -> 71 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line1_rtl.gifbin0 -> 64 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line2.gifbin0 -> 70 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line2_rtl.gifbin0 -> 64 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line3.gifbin0 -> 73 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line3_rtl.gifbin0 -> 67 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line4.gifbin0 -> 69 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/line4_rtl.gifbin0 -> 64 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/lock.gifbin0 -> 116 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus.gifbin0 -> 85 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus2.gifbin0 -> 92 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus2_rtl.gifbin0 -> 84 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus3.gifbin0 -> 93 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus3_rtl.gifbin0 -> 85 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus4.gifbin0 -> 90 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus4_rtl.gifbin0 -> 85 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus5.gifbin0 -> 87 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus5_rtl.gifbin0 -> 82 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/minus_ar.gifbin0 -> 68 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus.gifbin0 -> 89 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus2.gifbin0 -> 95 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus2_rtl.gifbin0 -> 88 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus3.gifbin0 -> 96 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus3_rtl.gifbin0 -> 89 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus4.gifbin0 -> 94 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus4_rtl.gifbin0 -> 89 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus5.gifbin0 -> 92 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus5_rtl.gifbin0 -> 87 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/plus_ar.gifbin0 -> 70 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/radio_off.gifbin0 -> 241 bytes
-rw-r--r--funcweb/funcweb/static/images/imgs/radio_on.gifbin0 -> 361 bytes
-rw-r--r--funcweb/funcweb/static/images/removebtn.jpgbin0 -> 1527 bytes
-rw-r--r--funcweb/funcweb/static/images/removebtnhover.jpgbin0 -> 1608 bytes
-rw-r--r--funcweb/funcweb/static/javascript/ajax.js99
-rw-r--r--funcweb/funcweb/static/javascript/async_tools.js10
-rw-r--r--funcweb/funcweb/static/javascript/dhtmlxcommon.js643
-rw-r--r--funcweb/funcweb/static/javascript/dhtmlxtree.js3742
-rw-r--r--funcweb/funcweb/static/javascript/ext/dhtmlxtree_dragin.js75
-rw-r--r--funcweb/funcweb/static/javascript/ext/dhtmlxtree_ed.js189
-rw-r--r--funcweb/funcweb/static/javascript/ext/dhtmlxtree_er.js80
-rw-r--r--funcweb/funcweb/static/javascript/ext/dhtmlxtree_json.js216
-rw-r--r--funcweb/funcweb/static/javascript/ext/dhtmlxtree_start.js101
-rw-r--r--funcweb/funcweb/static/javascript/jquery.js32
-rw-r--r--funcweb/funcweb/static/javascript/utils.js238
-rw-r--r--funcweb/funcweb/templates/add_group.html20
-rw-r--r--funcweb/funcweb/templates/async_table.html8
-rw-r--r--funcweb/funcweb/templates/glob_form.html13
-rw-r--r--funcweb/funcweb/templates/group_minion.html16
-rw-r--r--funcweb/funcweb/templates/group_small.html27
-rw-r--r--funcweb/funcweb/templates/groups_main.html19
-rw-r--r--funcweb/funcweb/templates/index.html19
-rw-r--r--funcweb/funcweb/templates/list_group.html16
-rw-r--r--funcweb/funcweb/templates/master.html34
-rw-r--r--funcweb/funcweb/templates/methods.html2
-rw-r--r--funcweb/funcweb/templates/minion_small.html28
-rw-r--r--funcweb/funcweb/templates/minions.html2
-rw-r--r--funcweb/funcweb/templates/modules.html2
-rw-r--r--funcweb/funcweb/templates/widgets.html2
-rw-r--r--funcweb/funcweb/tests/test_result_handler.py429
-rw-r--r--funcweb/funcweb/widget_automation.py12
-rw-r--r--funcweb/funcweb/widget_validation.py9
-rw-r--r--funcweb/setup.py5
-rw-r--r--test/unittest/test_groups.py3
119 files changed, 7844 insertions, 192 deletions
diff --git a/func/minion/func_arg.py b/func/minion/func_arg.py
index 5025e17..b405223 100644
--- a/func/minion/func_arg.py
+++ b/func/minion/func_arg.py
@@ -51,6 +51,7 @@ class ArgCompatibility(object):
'float':('range','min','max'),
'hash':('validator',),
'list':('validator',),
+ 'list*':('validator',),
}
diff --git a/func/minion/modules/certmastermod.py b/func/minion/modules/certmastermod.py
index 73f1468..a8a37e8 100644
--- a/func/minion/modules/certmastermod.py
+++ b/func/minion/modules/certmastermod.py
@@ -25,19 +25,17 @@ class CertMasterModule(func_module.FuncModule):
api_version = "0.0.1"
description = "Administers certs on an overlord."
- def get_hosts_to_sign(self, list_of_hosts):
+ def get_hosts_to_sign(self):
"""
...
"""
- list_of_hosts = self.__listify(list_of_hosts)
cm = certmaster.CertMaster()
return cm.get_csrs_waiting()
- def get_signed_certs(self, list_of_hosts):
+ def get_signed_certs(self):
"""
Returns a list of all signed certs on this minion
"""
- list_of_hosts = self.__listify(list_of_hosts)
cm = certmaster.CertMaster()
return cm.get_signed_certs()
@@ -65,5 +63,38 @@ class CertMasterModule(func_module.FuncModule):
if type(list_of_hosts) is type([]):
return list_of_hosts
else:
- return [ list_of_hosts ]
+ return [ list_of_hosts ]
+
+ def register_method_args(self):
+ """
+ Export certmaster module
+ """
+
+ list_of_hosts = {
+ 'type':'list',
+ 'optional':False,
+ 'description':'A list of hosts to apply the operation'
+ }
+ return {
+ 'get_hosts_to_sign':{
+ 'args':{},
+ 'description':"Returns a list of hosts to sign"
+ },
+ 'get_signed_certs':{
+ 'args':{},
+ 'description':"Get the certs you signed"
+ },
+ 'sign_hosts':{
+ 'args':{
+ 'list_of_hosts':list_of_hosts
+ },
+ 'description':"Sign a list of hosts"
+ },
+ 'cleanup_hosts':{
+ 'args':{
+ 'list_of_hosts':list_of_hosts
+ },
+ 'description':"Clean the certs for specified hosts"
+ }
+ }
diff --git a/func/minion/modules/command.py b/func/minion/modules/command.py
index 3d23e49..25a1aab 100644
--- a/func/minion/modules/command.py
+++ b/func/minion/modules/command.py
@@ -14,7 +14,7 @@ Abitrary command execution module for func.
"""
import func_module
-import sub_process
+from func.minion import sub_process
class Command(func_module.FuncModule):
@@ -47,3 +47,29 @@ class Command(func_module.FuncModule):
if os.access(command, os.X_OK):
return True
return False
+
+ def register_method_args(self):
+ """
+ The argument export method
+ """
+ #common type in both descriptions
+ command = {
+ 'type':'string',
+ 'optional':False,
+ 'description':'The command that is going to be used',
+ }
+
+ return {
+ 'run':{
+ 'args':{
+ 'command':command
+ },
+ 'description':'Run a specified command'
+ },
+ 'exists':{
+ 'args':{
+ 'command':command
+ },
+ 'description':'Check if specific command exists'
+ }
+ }
diff --git a/func/minion/modules/copyfile.py b/func/minion/modules/copyfile.py
index 150af88..8ae3351 100644
--- a/func/minion/modules/copyfile.py
+++ b/func/minion/modules/copyfile.py
@@ -46,6 +46,47 @@ class CopyFile(func_module.FuncModule):
return thissum.hexdigest()
+ def open(self, filepath, mode=None, uid=-1, gid=-1):
+ dirpath = os.path.dirname(filepath)
+ if not os.path.exists(dirpath):
+ os.makedirs(dirpath)
+
+ # Create empty file
+ try:
+ fo = open(filepath, 'w')
+ fo.close()
+ del fo
+ except (IOError, OSError), e:
+ # XXX logger output here
+ return -1
+
+ try:
+ # we could intify the mode here if it's a string
+ if mode:
+ os.chmod(filepath, mode)
+ if uid != -1 or gid != -1:
+ os.chown(filepath, uid, gid)
+ except (IOError, OSError), e:
+ return -1
+
+ return filepath
+
+ def append(self, filepath, filebuf):
+ if not os.path.exists(filepath):
+ # file disaperead
+ return -1
+
+ try:
+ fo = open(filepath, 'a')
+ fo.write(filebuf.data)
+ fo.close()
+ del fo
+ except (IOError, OSError), e:
+ # XXX logger output here
+ return -1
+
+ return 1
+
def copyfile(self, filepath, filebuf, mode=0644, uid=0, gid=0, force=None):
# -1 = problem file was not copied
diff --git a/func/minion/modules/echo.py b/func/minion/modules/echo.py
index 97afe42..471820d 100644
--- a/func/minion/modules/echo.py
+++ b/func/minion/modules/echo.py
@@ -40,14 +40,24 @@ class EchoTest(func_module.FuncModule):
Run a list
"""
return command
+
+
+ def run_list_star(self,*command):
+ """
+ Run a star list :)
+ """
+ return command
+
def run_hash(self,command):
"""
Run hash
"""
return command
-
+
+
+
def run_boolean(self,command):
"""
Run boolean
@@ -109,6 +119,17 @@ class EchoTest(func_module.FuncModule):
},
'description':'Returns back a list'
},
+ 'run_list_star':{
+ 'args':
+ {
+ 'command':{
+ 'type':'list*',
+ 'optional':False
+ }
+ },
+ 'description':'Prototype for *args'
+ },
+
'run_hash':{
'args':
{
@@ -119,6 +140,8 @@ class EchoTest(func_module.FuncModule):
},
'description':'Returns back a hash'
},
+
+
'run_boolean':{
'args':
{
diff --git a/func/minion/modules/filetracker.py b/func/minion/modules/filetracker.py
index f5f9dbb..6883fc1 100644
--- a/func/minion/modules/filetracker.py
+++ b/func/minion/modules/filetracker.py
@@ -190,3 +190,54 @@ class FileTracker(func_module.FuncModule):
break
m.update(d)
return m.hexdigest()
+
+ def register_method_args(self):
+ """
+ Implementing the argument getter part
+ """
+
+ return {
+ 'inventory':{
+ 'args':{
+ 'flatten':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':True,
+ 'description':"Show info in clean diffs"
+ },
+ 'checksum_enabled':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':True,
+ 'description':"Enable the checksum"
+ }
+ },
+ 'description':"Returns information on all tracked files"
+ },
+ 'track':{
+ 'args':{
+ 'file_name':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The file name to track (full path)"
+ },
+ 'full_scan':{
+ 'type':'int',
+ 'optional':True,
+ 'default':0,
+ 'description':"The 0 is for off and 1 is for on"
+ }
+ },
+ 'description':"Adds files to keep track of"
+ },
+ 'untrack':{
+ 'args':{
+ 'file_name':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The file name to untrack (full path)"
+ }
+ },
+ 'description':"Remove the track from specified file name"
+ }
+ }
diff --git a/func/minion/modules/hardware.py b/func/minion/modules/hardware.py
index 46b1821..5a72da4 100644
--- a/func/minion/modules/hardware.py
+++ b/func/minion/modules/hardware.py
@@ -72,6 +72,32 @@ class HardwareModule(func_module.FuncModule):
"""
return hw_info(with_devices)
+ def register_method_args(self):
+ """
+ Implementing the argument getter
+ """
+
+ return{
+ 'hal_info':{
+ 'args':{},
+ 'description':'Returns the output of lshal'},
+ 'inventory':{
+ 'args':{},
+ 'description':"The inventory part"
+ },
+ 'info':{
+ 'args':{
+ 'with_devices':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':True,
+ 'description':'All devices'
+ }
+ },
+ 'description':"A struct of hardware information"
+ }
+ }
+
# =================================
def hw_info(with_devices=True):
diff --git a/func/minion/modules/iptables/__init__.py b/func/minion/modules/iptables/__init__.py
index 937fe4b..db11a23 100644
--- a/func/minion/modules/iptables/__init__.py
+++ b/func/minion/modules/iptables/__init__.py
@@ -147,3 +147,124 @@ class Iptables(func_module.FuncModule):
self.policy("INPUT", "DROP")
self.policy("OUTPUT", "DROP")
self.policy("FORWARD", "DROP")
+
+ def register_method_args(self):
+ """
+ Implmenting the export arguments
+ """
+ ip={
+ 'type':'string',
+ 'optional':False,
+ 'default':'0.0.0.0'
+ }
+ chain={
+ 'type':'string',
+ 'optional':False,
+ 'default':'INPUT',
+ 'options':['INPUT','OUTPUT','FORWARD'],
+ 'description':"The chain to apply policy"
+ }
+
+ return {
+ 'run':{
+ 'args':{
+ 'args':{
+ 'type':'string',
+ 'optional':False,
+ 'default':"-L",
+ 'description':"The iptables command to send"
+ }
+ },
+ 'description':"Runs a iptables command"
+ },
+ 'policy':{
+ 'args':{
+ 'chain':chain,
+ 'policy':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"The policy to apply (optional)"
+ }
+
+ },
+ 'description':"Change/set the policy of the given chain,if no policy is given it checks the chain status"
+ },
+ 'flush':{
+ 'args':{
+ 'chain':chain
+ },
+ 'description':"Flush the given chain"
+ },
+ 'zero':{
+ 'args':{
+ 'chain':chain
+ },
+ 'description':"Zero counters in selected chain (or INPUT if none given)"
+ },
+ 'drop_from':{
+ 'args':{
+ 'ip':ip
+ },
+ 'description':"Drop all incomming traffic from IP"
+ },
+ 'reject_from':{
+ 'args':{
+ 'ip':ip
+ },
+ 'description':"Reject all incoming traffic from IP"
+ },
+ 'accept_from':{
+ 'args':{
+ 'ip':ip
+ },
+ 'description':"Accept all incoming traffic from IP"
+ },
+ 'drop_to':{
+ 'args':{
+ 'ip':ip
+ },
+ 'description':"Drop all outgoing traffic to IP."
+ },
+ 'reject_to':{
+ 'args':{
+ 'ip':ip
+ },
+ 'description':"Reject all outgoing traffic to IP"
+ },
+ 'accept_to':{
+ 'args':{
+ 'ip':ip
+ },
+ 'description':"Accept all outgoing traffic to IP."
+ },
+ 'inventory':{
+ 'args':{},
+ 'description':"The inventory part for that module"
+ },
+ 'dump':{
+ 'args':{
+ 'counters':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':False,
+ 'description':"Dump also the counters?"
+ }
+ },
+ 'description':"Dump iptables configuration in iptables-save format"
+ },
+ 'save':{
+ 'args':{
+ 'counters':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':False,
+ 'description':"Save also the counters?"
+ }
+ },
+ 'description':"Save iptables state using '/sbin/iptables-save'. If counters=True, save counters too."
+ },
+ 'panic':{
+ 'args':{},
+ 'description':"Drop all traffic (similar to 'service iptables panic')."
+ }
+ }
diff --git a/func/minion/modules/iptables/common.py b/func/minion/modules/iptables/common.py
index c5214f5..ab65ae0 100644
--- a/func/minion/modules/iptables/common.py
+++ b/func/minion/modules/iptables/common.py
@@ -10,7 +10,7 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# other modules
-import sub_process
+from func.minion import sub_process
def run_iptables(args):
cmd = sub_process.Popen(["/sbin/iptables"] + args.split(),
diff --git a/func/minion/modules/jboss.py b/func/minion/modules/jboss.py
index 58d4756..a7a3fa2 100644
--- a/func/minion/modules/jboss.py
+++ b/func/minion/modules/jboss.py
@@ -13,8 +13,8 @@
import func_module
-import sub_process
-import codes
+from func.minion import sub_process
+from func.minion import codes
import process
import networktest
import command
@@ -174,6 +174,76 @@ class JBoss(func_module.FuncModule):
return founded
+ def register_method_args(self):
+ """
+ Implementin the method argument getter part
+ """
+
+ return {
+ 'status':{
+ 'args':{},
+ 'description':"Get jboss information"
+ },
+ 'check':{
+ 'args':{
+ 'status':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"The status of instance to check (optional)"
+ }
+ },
+ 'description':"Check if jboss instances works"
+ },
+ 'search_by_port':{
+ 'args':{
+ 'port':{
+ 'type':'int',
+ 'optional':False,
+ 'min':0,
+ 'max':65535,
+ 'description':'The port to search for'
+ },
+ 'status':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"The status of instance to check (optional)"
+ }
+ },
+ 'description':"Search instance by listening port"
+ },
+ 'search_by_instance':{
+ 'args':{
+ 'instance':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the instance"
+ },
+ 'status':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"The status of the instance to search (optional)"
+ }
+ },
+ 'description':"Search instance by instance name"
+ },
+ 'search_by_address':{
+ 'args':{
+ 'address':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The bind adress to check"
+ },
+ 'status':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"The status of the instance to search (optional)"
+ }
+ },
+ 'description':"Search instance by bind address"
+
+ }
+ }
+
'''
def start(self, address="127.0.0.1", instance="default"):
"""
diff --git a/func/minion/modules/mount.py b/func/minion/modules/mount.py
index 0db914f..3c4abcc 100644
--- a/func/minion/modules/mount.py
+++ b/func/minion/modules/mount.py
@@ -12,8 +12,9 @@
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
-import sub_process, os
+import os
import func_module
+from func.minion import sub_process
class MountModule(func_module.FuncModule):
@@ -82,3 +83,79 @@ class MountModule(func_module.FuncModule):
def inventory(self, flatten=True):
return self.list()
+
+
+ def register_method_args(self):
+ """
+ Implementing the method arg getter
+ """
+
+ return{
+ 'list':{'args':{},
+ 'description':"Listing the mounting points"
+ },
+ 'mount':{
+ 'args':{
+ 'device':{
+ 'type':'string',
+ 'optional':False,
+ 'description':'The device to be mounted',
+ },
+ 'dir':{
+ 'type':'string',
+ 'optional':False,
+ 'description':'The directory which will the device mounted under'
+ },
+ 'type':{
+ 'type':'string',
+ 'optional':True,
+ 'default':'auto',
+ 'description':'The type of the mount'
+ },
+ 'options':{
+ 'type':'list',
+ 'optional':True,
+ 'description':"Some extra options to be added to mount command"
+ },
+ 'createdir':{
+ 'type':'boolean',
+ 'optional':True,
+ 'description':'Check if you want to create the dir place if not exist'
+ }
+ },
+ 'description':"Mount the specified device under some directory"
+ },
+ 'umount':{'args':{
+ 'dir':{
+ 'type':'string',
+ 'optional':False,
+ 'description':'The directory which will be unmounted'
+ },
+ 'killall':{
+ 'type':'boolean',
+ 'optional':True,
+ 'description':'The killal option'
+ },
+ 'force':{
+ 'type':'boolean',
+ 'optional':True,
+ 'description':'To force operation check it'
+ },
+ 'lazy':{
+ 'type':'boolean',
+ 'optional':True,
+ 'description':'The lazy option'
+ }
+ },
+ 'description':"Unmounting the specified directory."
+ },
+ 'inventory':{'args':{
+ 'flatten':{
+ 'type':'boolean',
+ 'optional':True,
+ 'description':"To flatten check."
+ }
+ },
+ 'description':"Th einventory part of that module"
+ }
+ }
diff --git a/func/minion/modules/nagios-check.py b/func/minion/modules/nagios-check.py
index f1c0714..89f2c61 100644
--- a/func/minion/modules/nagios-check.py
+++ b/func/minion/modules/nagios-check.py
@@ -32,3 +32,21 @@ class Nagios(func_module.FuncModule):
cmdref = sub_process.Popen(command.split(),stdout=sub_process.PIPE,stderr=sub_process.PIPE, shell=False)
data = cmdref.communicate()
return (cmdref.returncode, data[0], data[1])
+
+ def register_method_args(self):
+ """
+ Implementing argument getter part
+ """
+
+ return{
+ 'run':{
+ 'args':{
+ 'check_command':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The command to be checked"
+ }
+ },
+ 'description':"Runs a nagios check returning the return code"
+ }
+ }
diff --git a/func/minion/modules/netapp/common.py b/func/minion/modules/netapp/common.py
index 979c95c..9f664b0 100644
--- a/func/minion/modules/netapp/common.py
+++ b/func/minion/modules/netapp/common.py
@@ -13,7 +13,7 @@
##
import re
-import sub_process
+from func.minion import sub_process
SSH = '/usr/bin/ssh'
SSH_USER = 'root'
diff --git a/func/minion/modules/netapp/snap.py b/func/minion/modules/netapp/snap.py
index 8f3f209..ee113f7 100644
--- a/func/minion/modules/netapp/snap.py
+++ b/func/minion/modules/netapp/snap.py
@@ -47,3 +47,50 @@ class Snap(func_module.FuncModule):
"""
return True
+ def register_method_args(self):
+ """
+ Implementing the method argument getter part
+ """
+ vol = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the volume"
+ }
+ snap = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the snapshot"
+ }
+
+ filer = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"Resolvable name of the target filer"
+ }
+
+ return {
+ 'create':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol,
+ 'snap':snap
+ },
+ 'description':"Returns True if snapshot is created successfully"
+ },
+ 'delete':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol,
+ 'snap':snap
+ },
+ 'description':"Returns True if snapshot is delete successfully"
+ },
+ 'list':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol,
+ },
+ 'description':""
+ }
+ }
+
diff --git a/func/minion/modules/netapp/vol/__init__.py b/func/minion/modules/netapp/vol/__init__.py
index 14ce0ac..5cd4898 100644
--- a/func/minion/modules/netapp/vol/__init__.py
+++ b/func/minion/modules/netapp/vol/__init__.py
@@ -126,3 +126,82 @@ class Vol(func_module.FuncModule):
TODO: Document me ...
"""
pass
+
+ def register_method_args(self):
+ """
+ Implementing the method argument getter
+ """
+ vol = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the volume"
+ }
+
+ filer = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"Resolvable name of the target filer"
+ }
+
+ return {
+
+ 'create':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol,
+ 'aggr':{
+ 'type':'string',
+ 'optional':False,
+ 'description':'Aggregate in which to create the new volume (e.g. aggr0)'
+ },
+ 'size':{
+ 'type':'string',
+ 'optional':False,
+ 'description':'Size of the new volume (e.g. 500g)'
+ }
+ },
+ 'description':"Returns True if volume is created successfully"
+
+ },
+ 'destroy':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol
+ },
+ 'description':"Returns True if volume is successfully destroyed"
+
+ },
+ 'offline':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol
+ },
+ 'description':"Returns True if volume is successfully offlined"
+ },
+ 'online':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol
+ },
+ 'description':"Returns True if volume is successfully onlined"
+ },
+ 'status':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol
+ },
+ 'description':"If vol is not given, returns a list of dictionaries containing the status information of each volume in the system If vol is given, return just the dictionary for the given volume "
+ },
+ 'size':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol,
+ 'delta':{
+ 'type':'string',
+ 'optional':True,
+ 'description':'Optional change in size (e.g. +200g or -50g)'
+ }
+ },
+ 'description':"If delta is not given, return the size of the given volume (e.g. '500g') If delta is given, return True if volume is successfully resized "
+ }
+ }
diff --git a/func/minion/modules/netapp/vol/clone.py b/func/minion/modules/netapp/vol/clone.py
index 715d8a8..ff924d0 100644
--- a/func/minion/modules/netapp/vol/clone.py
+++ b/func/minion/modules/netapp/vol/clone.py
@@ -42,5 +42,48 @@ class Clone(func_module.FuncModule):
output = ssh(filer, cmd_opts)
return check_output(regex, output)
+
+ def register_method_args(self):
+ """
+ Implementing netapp.clone export
+ """
+ vol = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the volume"
+ }
+
+ filer = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"Resolvable name of the target filer"
+ }
+
+ snap = {
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the snapshot"
+ }
-
+ return {
+ 'create':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol,
+ 'snap':snap,
+ 'parent':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The parent to clone"
+ }
+ },
+ 'description':"Create a clone"
+ },
+ 'split':{
+ 'args':{
+ 'filer':filer,
+ 'vol':vol
+ },
+ 'description':"Split the vol"
+ }
+ }
diff --git a/func/minion/modules/networktest.py b/func/minion/modules/networktest.py
index 0e6fbb2..53fd453 100644
--- a/func/minion/modules/networktest.py
+++ b/func/minion/modules/networktest.py
@@ -10,9 +10,8 @@
import func_module
-from codes import FuncException
-
-import sub_process
+from func.minion.codes import FuncException
+from func.minion import sub_process
class NetworkTest(func_module.FuncModule):
@@ -62,3 +61,67 @@ class NetworkTest(func_module.FuncModule):
full_cmd = [command] + opts
cmd = sub_process.Popen(full_cmd, stdout=sub_process.PIPE)
return [line for line in cmd.communicate()[0].split('\n')]
+
+ def register_method_args(self):
+ """
+ Implementing method getter part
+ """
+
+ return{
+ 'ping':{
+ 'args':{
+ 'args':{
+ 'type':'list*',
+ 'optional':False,
+ 'description':"Options for ping command"
+ }
+ },
+ 'description':"Ping command utility"
+ },
+ 'netstat':{
+ 'args':{
+ 'args':{
+ 'type':'list*',
+ 'optional':False,
+ 'description':"Options for netstat command"
+ }},
+ 'description':"The unix netstat command utility"
+ },
+ 'traceroute':{
+ 'args':{
+ 'args':{
+ 'type':'list*',
+ 'optional':False,
+ 'description':"Options for traceroute command"
+
+ }},
+ 'description':"Traceroute network utility"
+ },
+ 'dig':{
+ 'args':{
+ 'args':{
+ 'type':'list*',
+ 'optional':False,
+ 'description':"Options for dig command"
+
+ }},
+ 'description':"Dig command utility"
+ },
+ 'isportopen':{
+ 'args':{
+ 'host':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the host to be checked"
+ },
+ 'port':{
+ 'type':'int',
+ 'optional':False,
+ 'min':0,
+ 'max':65535,
+ 'description':'The port to be checked on specified host'
+ }
+ },
+ 'description':"Checks if port is open for specified host"
+ }
+ }
diff --git a/func/minion/modules/overlord.py b/func/minion/modules/overlord.py
index 743c672..7195019 100644
--- a/func/minion/modules/overlord.py
+++ b/func/minion/modules/overlord.py
@@ -45,5 +45,23 @@ class OverlordModule(func_module.FuncModule):
else:
maphash[current_minion] = {}
return maphash
+
+ def register_method_args(self):
+ """
+ Export overlord
+ """
+ return {
+ 'map_minions':{
+ 'args':{
+ 'get_only_alive':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':True,
+ 'description':"Get only online ones"
+ }
+ },
+ 'description':"Builds a recursive map of the minions currently assigned to this minion overlord"
+ }
+ }
diff --git a/func/minion/modules/process.py b/func/minion/modules/process.py
index 22141c3..80e76fd 100644
--- a/func/minion/modules/process.py
+++ b/func/minion/modules/process.py
@@ -14,8 +14,8 @@
##
# other modules
-import sub_process
-import codes
+from func.minion import sub_process
+from func.minion import codes
# our modules
import func_module
@@ -218,3 +218,55 @@ class ProcessModule(func_module.FuncModule):
rc = sub_process.call(["/usr/bin/pkill", name, level],
executable="/usr/bin/pkill", shell=False)
return rc
+
+ def register_method_args(self):
+ """
+ Implementing the argument getter
+ """
+ return{
+ 'info':{
+ 'args':{
+ 'flags':{
+ 'type':'string',
+ 'default':'-auxh',
+ 'optional':True,
+ 'description':"Flags for ps command"
+ }
+ },
+ 'description':'Get the process info for system'
+ },
+ 'mem':{
+ 'args':{},
+ 'description':"Returns a list of per-program memory usage."
+ },
+ 'kill':{
+ 'args':{
+ 'pid':{
+ 'type':'int',
+ 'optional':False,
+ 'description':"The pid for process to be killed"
+ },
+ 'signal':{
+ 'type':'string',
+ 'optional':True,
+ 'default':"TERM",
+ 'description':"Signal to send before killing"
+ }
+ },
+ "description":"Kill a process with proper signal"
+ },
+ 'pkill':{
+ 'args':{
+ 'name':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of the app but with full path info ." },
+ 'level':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"Level of killing"
+ }
+ },
+ "description":"Kill an app with supplying a name and level"
+ }
+ }
diff --git a/func/minion/modules/reboot.py b/func/minion/modules/reboot.py
index c4fb275..70a4db0 100644
--- a/func/minion/modules/reboot.py
+++ b/func/minion/modules/reboot.py
@@ -9,7 +9,7 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import func_module
-import sub_process
+from func.minion import sub_process
class Reboot(func_module.FuncModule):
@@ -19,3 +19,28 @@ class Reboot(func_module.FuncModule):
def reboot(self, when='now', message=''):
return sub_process.call(["/sbin/shutdown", '-r', when, message])
+
+ def register_method_args(self):
+ """
+ Implementing method getter part
+ """
+
+ return {
+ 'reboot':{
+ 'args':{
+ 'when':{
+ 'type':'string',
+ 'optional':True,
+ 'default':'now',
+ 'description':"When to reboot (optional)"
+ },
+ 'message':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"The shutdown message"
+ }
+ },
+ 'description':"Rebooting the minions"
+ }
+ }
+
diff --git a/func/minion/modules/rpms.py b/func/minion/modules/rpms.py
index 66d9129..f271406 100644
--- a/func/minion/modules/rpms.py
+++ b/func/minion/modules/rpms.py
@@ -67,3 +67,38 @@ class RpmModule(func_module.FuncModule):
else:
results.append([name, epoch, version, release, arch])
return results
+
+ def register_method_args(self):
+ """
+ Implementing the method argument getter
+ """
+
+ return {
+ 'inventory':{
+ 'args':{
+ 'flatten':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':True,
+ 'description':"Print clean in difss"
+ }
+ },
+ 'description':"Returns information on all installed packages"
+ },
+ 'glob':{
+ 'args':{
+ 'pattern':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The glob packet pattern"
+ },
+ 'flatten':{
+ 'type':'boolean',
+ 'optional':True,
+ 'default':True,
+ 'description':"Print clean in difss"
+ }
+ },
+ 'description':"Return a list of installed packages that match a pattern"
+ }
+ }
diff --git a/func/minion/modules/smart.py b/func/minion/modules/smart.py
index f410f09..e8e4844 100644
--- a/func/minion/modules/smart.py
+++ b/func/minion/modules/smart.py
@@ -45,3 +45,22 @@ class SmartModule(func_module.FuncModule):
results.append(x)
return (cmd.returncode, results)
+
+ def register_method_args(self):
+ """
+ Implementing method argument getter
+ """
+
+ return {
+ 'info':{
+ 'args':{
+ 'flags':{
+ 'type':'string',
+ 'optional':True,
+ 'default':'-q onecheck',
+ 'description':"Flags for smart command"
+ }
+ },
+ 'description':"Grabs status from SMART to see if your hard drives are ok."
+ }
+ }
diff --git a/func/minion/modules/snmp.py b/func/minion/modules/snmp.py
index c992db1..c06655d 100644
--- a/func/minion/modules/snmp.py
+++ b/func/minion/modules/snmp.py
@@ -14,7 +14,7 @@ Abitrary command execution module for func.
"""
import func_module
-import sub_process
+from func.minion import sub_process
base_snmp_command = '/usr/bin/snmpget -v2c -Ov -OQ'
class Snmp(func_module.FuncModule):
@@ -32,7 +32,35 @@ class Snmp(func_module.FuncModule):
cmdref = sub_process.Popen(command.split(),stdout=sub_process.PIPE,stderr=sub_process.PIPE, shell=False)
data = cmdref.communicate()
return (cmdref.returncode, data[0], data[1])
+
+ def register_method_args(self):
+ """
+ Implementing the argument getter
+ """
+ return {
+ 'get':{
+ 'args':{
+ 'oid':{
+ 'type':'string',
+ 'optional':False,
+ 'description':'The oid'
+ },
+ 'rocommunity':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The rocommunity"
+ },
+ 'hostname':{
+ 'type':'string',
+ 'optional':True,
+ 'default':'localhost',
+ 'description':"The hostname tobe apllied on"
+ }
+ },
+ 'description':"Runs an snmpget on a specific oid returns the output of the call"
+ }
+ }
#def walk(self, oid, rocommunity):
#def table(self, oid, rocommunity):
diff --git a/func/minion/modules/sysctl.py b/func/minion/modules/sysctl.py
index 1f11d55..36b5605 100644
--- a/func/minion/modules/sysctl.py
+++ b/func/minion/modules/sysctl.py
@@ -29,3 +29,41 @@ class SysctlModule(func_module.FuncModule):
def set(self, name, value):
return self.__run("/sbin/sysctl -w %s=%s" % (name, value))
+
+ def register_method_args(self):
+ """
+ Implementing the method argument getter
+ """
+
+ return {
+ 'list':{
+ 'args':{},
+ 'description':"Display all values currently available."
+ },
+ 'get':{
+ 'args':{
+ 'name':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of a key to read from. An example is kernel.ostype"
+ }
+ },
+ 'description':"Use this option to disable printing of the key name when printing values"
+ },
+ 'set':{
+ 'args':{
+ 'name':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name of a key to read from. An example is kernel.ostype"
+ },
+ 'value':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The name value to be set."
+ }
+
+ },
+ 'description':"Use this option when you want to change a sysctl setting"
+ }
+ }
diff --git a/func/minion/modules/test.py b/func/minion/modules/test.py
index 77324c4..4006f8a 100644
--- a/func/minion/modules/test.py
+++ b/func/minion/modules/test.py
@@ -33,3 +33,55 @@ class Test(func_module.FuncModule):
Returns whatever was passed into it
"""
return data
+
+ def register_method_args(self):
+ """
+ Implementing method argument getter
+ """
+
+ return {
+ 'add':{
+ 'args':{
+ 'numb1':{
+ 'type':'int',
+ 'optional':False,
+ 'description':'An int'
+ },
+ 'numb2':{
+ 'type':'int',
+ 'optional':False,
+ 'description':'An int'
+ }
+
+ },
+ 'description':'Gives back the sum of 2 integers'
+ },
+ 'ping':{
+ 'args':{},
+ 'description':"Ping the minion"
+ },
+ 'sleep':{
+ 'args':{
+ 't':{
+ 'type':'int',
+ 'optional':False,
+ 'description':'Num of sec'
+ }
+ },
+ 'description':"Sleep for a while"
+ },
+ 'explode':{
+ 'args':{},
+ 'description':"Raises an exception"
+ },
+ 'echo':{
+ 'args':{
+ 'data':{
+ 'type':'string',
+ 'optional':False,
+ 'description':"The message to send"
+ }
+ },
+ 'description':"Echoes back the sent data "
+ }
+ }
diff --git a/func/minion/modules/yumcmd.py b/func/minion/modules/yumcmd.py
index 072b907..a35b104 100644
--- a/func/minion/modules/yumcmd.py
+++ b/func/minion/modules/yumcmd.py
@@ -69,3 +69,36 @@ class Yum(func_module.FuncModule):
pkg_list = exactmatch + matched
return map(str, pkg_list)
+
+ def register_method_args(self):
+ """
+ Implementing the argument getter
+ """
+
+ return{
+ 'update':{
+ 'args':{
+ 'pkg':{
+ 'type':'string',
+ 'optional':True,
+ 'description':"The yum pattern for updating package"
+ }
+ },
+ 'description':"Updating system according to a specified pattern"
+ },
+ 'check_update':{
+ 'args':{
+ 'filter':{
+ 'type':'list',
+ 'optional':True,
+ 'description':"A list of what you want to update"
+ },
+ 'repo':{
+ 'type':'string',
+ 'optional':True,
+ 'description':'Repo name to use for that update'
+ }
+ },
+ 'description':"Cheking for updates with supplied filter patterns and repo"
+ }
+ }
diff --git a/func/overlord/client.py b/func/overlord/client.py
index 54777e3..9e4b0dc 100755
--- a/func/overlord/client.py
+++ b/func/overlord/client.py
@@ -294,7 +294,7 @@ class Overlord(object):
if method in self.methods.keys():
return self.methods[method](*args)
else:
- raise AttributeError("no such method")
+ raise AttributeError("No such local method: %s" % method)
if not self.delegate: #delegation is turned off, so run normally
return self.run_direct(module, method, args, nforks)
diff --git a/func/overlord/cmd_modules/call.py b/func/overlord/cmd_modules/call.py
index 0743442..e1674fe 100644
--- a/func/overlord/cmd_modules/call.py
+++ b/func/overlord/cmd_modules/call.py
@@ -160,6 +160,7 @@ class Call(base_command.BaseCommand):
print "JOB_ID:", pprint.pformat(results)
return results
else:
+
return self.overlord_obj.local.utils.async_poll(results, self.print_results)
# dump the return code stuff atm till we figure out the right place for it
diff --git a/func/overlord/cmd_modules/copyfile.py b/func/overlord/cmd_modules/copyfile.py
index c8bc7e8..711c4dd 100644
--- a/func/overlord/cmd_modules/copyfile.py
+++ b/func/overlord/cmd_modules/copyfile.py
@@ -49,19 +49,5 @@ class CopyFile(base_command.BaseCommand):
self.server_spec = self.parentCommand.server_spec
self.getOverlord()
-
- try:
- fb = open(self.options.filename, "r").read()
- except IOError, e:
- sys.stderr.write("Unable to open file: %s: %s\n" % (self.options.filename, e))
- return
-
- st = os.stat(self.options.filename)
- mode = stat.S_IMODE(st.st_mode)
- uid = st.st_uid
- gid = st.st_gid
-
- data = xmlrpclib.Binary(fb)
- results = self.overlord_obj.run("copyfile", "copyfile", [self.options.remotepath, data,
- mode, uid, gid])
+ return self.overlord_obj.local.copyfile.send(self.options.filename, self.options.remotepath)
diff --git a/func/overlord/modules/copyfile.py b/func/overlord/modules/copyfile.py
new file mode 100644
index 0000000..2954462
--- /dev/null
+++ b/func/overlord/modules/copyfile.py
@@ -0,0 +1,27 @@
+from func.overlord import overlord_module
+import os
+import stat
+import xmlrpclib
+
+class copyfile(overlord_module.BaseModule):
+ def send(self, localpath, remotepath, bufsize=60000):
+ try:
+ f = open(localpath, "r")
+ except IOError, e:
+ sys.stderr.write("Unable to open file: %s: %s\n" % (self.options.filename, e))
+ return
+
+ st = os.stat(localpath)
+ mode = stat.S_IMODE(st.st_mode)
+ uid = st.st_uid
+ gid = st.st_gid
+
+ self.parent.run("copyfile", "open", [remotepath, mode, uid, gid])
+
+ while True:
+ data=f.read(bufsize)
+ if data:
+ self.parent.run("copyfile", "append", [remotepath, xmlrpclib.Binary(data)])
+ else:
+ break
+
diff --git a/funcweb/Makefile b/funcweb/Makefile
index 4d1e644..1a54edf 100755
--- a/funcweb/Makefile
+++ b/funcweb/Makefile
@@ -77,6 +77,7 @@ unittest:
rpms: build sdist
mkdir -p rpm-build
cp dist/*.gz rpm-build/
+ cp funcweb.te rpm-build/
cp version rpm-build/
rpmbuild --define "_topdir %(pwd)/rpm-build" \
--define "_builddir %{_topdir}" \
diff --git a/funcweb/etc/pam.d/funcweb b/funcweb/etc/pam.d/funcweb
new file mode 100644
index 0000000..658583d
--- /dev/null
+++ b/funcweb/etc/pam.d/funcweb
@@ -0,0 +1,3 @@
+#%PAM-1.0
+auth include system-auth
+account include system-auth
diff --git a/funcweb/funcweb.spec b/funcweb/funcweb.spec
index df5aee7..7ea73c1 100644
--- a/funcweb/funcweb.spec
+++ b/funcweb/funcweb.spec
@@ -12,15 +12,19 @@ Release: %(echo `awk '{ print $2 }' %{SOURCE1}`)%{?dist}
License: GPLv2+
Group: Applications/System
Source0: %{name}-%{version}.tar.gz
+Source2: %{name}.te
#packages that are required
Requires: python >= 2.3
Requires: func >= 0.20
-Requires: certmaster >= 0.1
+Requires: certmaster >= 0.20
Requires: mod_ssl >= 2.0
Requires: httpd >= 2.0
Requires: TurboGears >= 1.0.4.2
Requires: pam
+#a bug in Turbogears package that causes some problems if
+#bigger version than that one is installed on the system !
+Requires: python-cherrypy < 3.0
#the build requires
BuildRequires: python-devel
@@ -34,6 +38,12 @@ BuildRequires: python-setuptools-devel
BuildRequires: python-setuptools
%endif
%endif
+# SELinux module
+%if 0%{?fedora} == 5
+BuildRequires: checkpolicy, selinux-policy >= 2.2.40, m4
+%else
+BuildRequires: checkpolicy, selinux-policy-devel
+%endif
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
BuildArch: noarch
Url: https://hosted.fedoraproject.org/projects/func/
@@ -41,8 +51,21 @@ Url: https://hosted.fedoraproject.org/projects/func/
Web interface for managing systems controlled by Func
+%package selinux
+Summary: SELinux support for FuncWeb
+Group: System Environment/Daemons
+Requires: %{name} = %{version}
+Requires(post): policycoreutils, initscripts, %{name}
+Requires(preun): policycoreutils, initscripts, %{name}
+Requires(postun): policycoreutils
+
+%description selinux
+This package adds SELinux policy for FuncWeb
+
%prep
%setup -q
+mkdir -p selinux
+cp -p %{SOURCE2} selinux/
%build
%{__python} setup.py build
@@ -51,6 +74,11 @@ Web interface for managing systems controlled by Func
test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%{__python} setup.py install --prefix=/usr --root=$RPM_BUILD_ROOT
+#SELinux part
+cd selinux/
+make -f %{_datadir}/selinux/devel/Makefile
+install -p -m 644 -D %{name}.pp $RPM_BUILD_ROOT%{_datadir}/selinux/packages/%{name}/%{name}.pp
+
%clean
rm -fr $RPM_BUILD_ROOT
@@ -67,12 +95,14 @@ rm -fr $RPM_BUILD_ROOT
%dir %{python_sitelib}/funcweb/static
%dir %{python_sitelib}/funcweb/static/css
%dir %{python_sitelib}/funcweb/static/images
-%dir %{python_sitelib}/funcweb/static/javascript
+%dir %{python_sitelib}/funcweb/static/images/imgs
+%dir %{python_sitelib}/funcweb/static/javascript/ext
%dir %{python_sitelib}/funcweb/identity
%dir %{_sysconfdir}/%{name}
%dir /var/log/funcweb
%config(noreplace) %{_sysconfdir}/httpd/conf.d/funcweb.conf
%config(noreplace) %{_sysconfdir}/%{name}/prod.cfg
+%config(noreplace) %{_sysconfdir}/pam.d/funcweb
%config(noreplace) /etc/logrotate.d/funcweb_rotate
#adding the server startup shutdown thing
@@ -95,14 +125,20 @@ rm -fr $RPM_BUILD_ROOT
%{python_sitelib}/funcweb/static/images/*.jpg
%{python_sitelib}/funcweb/static/images/*.ico
%{python_sitelib}/funcweb/static/images/*.gif
+%{python_sitelib}/funcweb/static/images/imgs/*.gif
%{python_sitelib}/funcweb/static/images/Makefile
%{python_sitelib}/funcweb/static/javascript/*.js
+%{python_sitelib}/funcweb/static/javascript/ext/*.js
%{python_sitelib}/funcweb/static/javascript/Makefile
%{python_sitelib}/funcweb/identity/*.py*
%{python_sitelib}/funcweb/identity/Makefile
/usr/bin/funcwebd
%doc README
+%files selinux
+%defattr(-, root, root, -)
+%{_datadir}/selinux/packages/%{name}/%{name}.pp
+
%post
# for suse
if [ -x /usr/lib/lsb/install_initd ]; then
@@ -120,6 +156,24 @@ else
done
fi
+%post selinux
+if [ "$1" -le "1" ]; then # Fist install
+ semodule -i %{_datadir}/selinux/packages/%{name}/%{name}.pp 2>/dev/null || :
+ semanage port -a -t funcweb_port_t -p tcp 51236 2>/dev/null || :
+fi
+
+%preun selinux
+if [ "$1" -lt "1" ]; then # Final removal
+ semanage port -d -t funcweb_port_t -p tcp 51236 2>/dev/null || :
+ semodule -r funcweb 2>/dev/null || :
+fi
+
+%postun selinux
+if [ "$1" -ge "1" ]; then # Upgrade
+ # Replaces the module if it is already loaded
+ semodule -i %{_datadir}/selinux/packages/%{name}/%{name}.pp 2>/dev/null || :
+fi
+
#before uninstall the things
%preun
if [ "$1" = 0 ] ; then
@@ -135,6 +189,9 @@ fi
%changelog
+* Fri Jul 11 2008 Krzysztof A. Adamski <krzysztofa@gmail.com> - 0.1
+- SELinux policy added
+
* Sat Jul 05 2008 Denis Kurov <makkalot@gmail.com> - 0.1
- The first RPM for funcweb with new dynamic widget stuff
diff --git a/funcweb/funcweb.te b/funcweb/funcweb.te
new file mode 100644
index 0000000..1e610ae
--- /dev/null
+++ b/funcweb/funcweb.te
@@ -0,0 +1,12 @@
+module funcweb 1.0.0;
+
+require {
+ type httpd_t;
+ type port_t;
+ attribute port_type;
+ class tcp_socket name_connect;
+}
+
+type funcweb_port_t, port_type;
+
+allow httpd_t funcweb_port_t:tcp_socket name_connect;
diff --git a/funcweb/funcweb/commands.py b/funcweb/funcweb/commands.py
index 6d6d338..aa74680 100644
--- a/funcweb/funcweb/commands.py
+++ b/funcweb/funcweb/commands.py
@@ -18,9 +18,12 @@ cherrypy.lowercase_api = True
class ConfigurationError(Exception):
pass
+#that variable will help us to see when we are in PRODUCTION
+PRODUCTION_ENV = False
+
def start():
"""Start the CherryPy application server."""
-
+ global PRODUCTION_ENV
setupdir = dirname(dirname(__file__))
curdir = os.getcwd()
@@ -32,6 +35,8 @@ def start():
# 'prod.cfg' in the current directory and then for a default
# config file called 'default.cfg' packaged in the egg.
if exists("/etc/funcweb/prod.cfg"):
+ #we work with production settings now !
+ PRODUCTION_ENV = True
configfile = "/etc/funcweb/prod.cfg"
elif len(sys.argv) > 1:
@@ -53,7 +58,7 @@ def start():
from funcweb.controllers import Root
- if exists("/etc/funcweb/prod.cfg"):
+ if PRODUCTION_ENV:
utils.daemonize("/var/run/funcwebd.pid")
#then start the server
try:
diff --git a/funcweb/funcweb/controllers.py b/funcweb/funcweb/controllers.py
index 2bdbe80..43f60e3 100644
--- a/funcweb/funcweb/controllers.py
+++ b/funcweb/funcweb/controllers.py
@@ -7,10 +7,13 @@ from funcweb.widget_automation import WidgetListFactory,RemoteFormAutomation,Rem
from funcweb.widget_validation import WidgetSchemaFactory
from funcweb.async_tools import AsyncResultManager
from func.jobthing import purge_old_jobs,JOB_ID_RUNNING,JOB_ID_FINISHED,JOB_ID_PARTIAL
-
+from func.utils import is_error
# it is assigned into method_display on every request
global_form = None
+####**NOTE : All flash messages are used for error and some weird sitaution's reporting be careful when using
+#that turbogears functionality !
+
def validate_decorator_updater(validator_value=None):
"""
When we pass the global_form directly to
@@ -43,31 +46,46 @@ class Funcweb(object):
}
async_manager = None
first_run = True
+ group_name = None # a cache variable for current group_name
#will be reused for widget validation
- @expose(allow_json=True)
- @identity.require(identity.not_anonymous())
- def minions(self, glob='*',submit=None):
- """ Return a list of our minions that match a given glob """
- #make the cache thing
-
+ def get_current_minion_list(self,glob):
+ """
+ That method will not be reachable from web interface it just
+ a util method that gives back the current minion list back,
+ we use that minion glob form in lots of places so it is a hack
+ to avoid writing stupid code again and again :)
+ """
+
if self.func_cache['glob'] == glob:
minions = self.func_cache['minions']
else:
#we dont have it it is for first time so lets pull it
- minions=Minions(glob).get_all_hosts()
- self.func_cache['glob']=glob
- self.func_cache['minions']=minions
+ try:
+ minions=Minions(glob).get_all_hosts()
+ self.func_cache['glob']=glob
+ self.func_cache['minions']=minions
+ except Exception,e:
+ #TODO log here
+ minions = []
+ return minions
+
+ @expose(allow_json=True)
+ @identity.require(identity.not_anonymous())
+ def minions(self, glob='*',submit=None):
+ """ Return a list of our minions that match a given glob """
+ #make the cache thing
+ minions = self.get_current_minion_list(glob)
if not submit:
- return dict(minions=minions,tg_template="funcweb.templates.index")
+ return dict(minions=minions,submit_adress="/funcweb/minions",tg_template="funcweb.templates.index")
else:
- return dict(minions=minions,tg_template="funcweb.templates.minions")
+ return dict(minions=minions,submit_adress="/funcweb/minions",tg_template="funcweb.templates.minions")
index = minions # start with our minion view, for now
- @expose(template="funcweb.templates.modules")
+ @expose(allow_json = True)
@identity.require(identity.not_anonymous())
def minion(self, name="*", module=None, method=None):
""" Display module or method details for a specific minion.
@@ -93,14 +111,29 @@ class Funcweb(object):
if not module:
if not self.func_cache['modules']:
- modules = fc.system.list_modules()
+ try :
+ modules = fc.system.list_modules()
+ if modules.has_key(name) and is_error(modules[name]):
+ #TODO put logger here!
+ flash("Some exception while getting the module list for %s minion"%(name))
+ return dict()
+
+ except Exception,e:
+ flash("Some exception while getting the module list for %s minion"%(name))
+ #it is an error case
+ return dict()
display_modules = []
for module in modules.itervalues():
for mod in module:
#if it is not empty
- if getattr(fc,mod).get_method_args()[name]:
- display_modules.append(mod)
+ try :
+ if getattr(fc,mod).get_method_args()[name]:
+ display_modules.append(mod)
+ except Exception,e:
+ #TODO logger
+ flash("Some exception while getting the argument list for %s module"%(mod))
+ return dict()
#put it into the cache to make that slow thing faster
self.func_cache['modules']=display_modules
@@ -112,8 +145,8 @@ class Funcweb(object):
modules = {}
modules[name]=display_modules
-
- return dict(modules=modules)
+
+ return dict(modules=modules,tg_template = "funcweb.templates.modules")
else: # a module is specified
if not method: # return a list of methods for specified module
#first check if we have it into the cache
@@ -124,8 +157,13 @@ class Funcweb(object):
else:
self.func_cache['module_name']= module
#display the list only that is registered with register_method template !
- registered_methods=getattr(fc,module).get_method_args()[name].keys()
- modules = getattr(fc, module).list_methods()
+ try:
+ registered_methods=getattr(fc,module).get_method_args()[name].keys()
+ modules = getattr(fc, module).list_methods()
+ except Exception,e:
+ flash("Some error in getting method list for %s module "%(module))
+ return dict()
+
for mods in modules.itervalues():
from copy import copy
cp_mods = copy(mods)
@@ -162,8 +200,16 @@ class Funcweb(object):
self.func_cache['methods']=None
#get the method args
- method_args = getattr(fc,module).get_method_args()
-
+ try:
+ method_args = getattr(fc,module).get_method_args()
+ if method_args.has_key(minion) and is_error(method_args[minion]):
+ flash("We encountered some error when getting method args for %s.%s.%s"%(minion,module,method))
+ return dict()
+
+ except Exception,e:
+ flash("We encountered some error when getting method args for %s.%s.%s"%(minion,module,method))
+ return dict()
+
if not method_args.values():
#print "Not registered method here"
return dict(minion_form = None,minion=minion,module=module,method=method)
@@ -175,19 +221,23 @@ class Funcweb(object):
else:
description = None
if minion_arguments:
- wlist_object = WidgetListFactory(minion_arguments,minion=minion,module=module,method=method)
- wlist_object = wlist_object.get_widgetlist_object()
- #create the validation parts for the remote form
- wf = WidgetSchemaFactory(minion_arguments)
- schema_man=wf.get_ready_schema()
-
- #create the final form
- minion_form = RemoteFormAutomation(wlist_object,schema_man)
- global_form = minion_form.for_widget
- #print global_form
- #i use that when something goes wrong to check the problem better to stay here ;)
- #self.minion_form =RemoteFormFactory(wlist_object,schema_man).get_remote_form()
-
+ try:
+ wlist_object = WidgetListFactory(minion_arguments,minion=minion,module=module,method=method)
+ wlist_object = wlist_object.get_widgetlist_object()
+ #create the validation parts for the remote form
+ wf = WidgetSchemaFactory(minion_arguments)
+ schema_man=wf.get_ready_schema()
+
+ #create the final form
+ minion_form = RemoteFormAutomation(wlist_object,schema_man)
+ global_form = minion_form.for_widget
+ #print global_form
+ #i use that when something goes wrong to check the problem better to stay here ;)
+ #self.minion_form =RemoteFormFactory(wlist_object,schema_man).get_remote_form()
+ except Exception,e:
+ flash("We got some exception when rendering the %s.%s.%s"%(minion,module,method))
+ return dict()
+
del wlist_object
del minion_arguments
@@ -277,38 +327,57 @@ class Funcweb(object):
#get again the method args to get their order :
- arguments=getattr(fc,module).get_method_args()
+ try:
+ arguments=getattr(fc,module).get_method_args()
+ if arguments.has_key(minion) and is_error(arguments[minion]):
+ flash("Encountered some error when trying to get method arguments for %s.%s.%s"%(minion,module,method))
+ return dict()
+
+ except Exception,e:
+ flash("Encountered some error when trying to get method arguments for %s.%s.%s"%(minion,module,method))
+ return dict()
#so we know the order just allocate and put them there
- cmd_args=['']*(len(kw.keys()))
-
+ cmd_args=[]
+
+ #firstly create a better dict to lookup
+ sorted_args = {}
for arg in kw.keys():
#wow what a lookup :)
- index_of_arg = arguments[minion][method]['args'][arg]['order']
- cmd_args[index_of_arg]=kw[arg]
-
+ tmp_arg_num = arguments[minion][method]['args'][arg]['order']
+ sorted_args[tmp_arg_num] = []
+ sorted_args[tmp_arg_num].append(arg)
+ sorted_args[tmp_arg_num].append(kw[arg])
+
+ #now append them to main cmd args
+ #not a very efficient algorithm i know i know :|
+ ordered_keys = sorted_args.keys()
+ ordered_keys.sort()
+ for order_key in ordered_keys:
+ current_argument_name = sorted_args[order_key][0]
+ current_argument = sorted_args[order_key][1]
+ current_type = arguments[minion][method]['args'][current_argument_name]['type']
+ #for *args types
+ if current_type == "list*":
+ for list_arg in current_argument:
+ cmd_args.append(list_arg)
+ else:
+ cmd_args.append(current_argument)
+
+ #print "The list to be send is : ",cmd_args
#now execute the stuff
#at the final execute it as a multiple if the glob suits for that
#if not (actually there shouldnt be an option like that but who knows :))
#it will run as a normal single command to clicked minion
- if self.func_cache['glob']:
- fc_async = Overlord(self.func_cache['glob'],async=True)
+ try:
+ if self.func_cache['glob']:
+ fc_async = Overlord(self.func_cache['glob'],async=True)
- result_id = getattr(getattr(fc_async,module),method)(*cmd_args)
- result = "".join(["The id for current job is :",str(result_id)," You will be notified when there is some change about that command !"])
+ result_id = getattr(getattr(fc_async,module),method)(*cmd_args)
+ result = "".join(["The id for current job is :",str(result_id)," You will be notified when there is some change about that command !"])
- #that part gives a chance for short methods to finish their jobs and display them
- #immediately so user will not wait for new notifications for that short thing
- import time
- time.sleep(4)
- tmp_as_res = fc_async.job_status(result_id)
- if tmp_as_res[0] == JOB_ID_FINISHED:
- result = tmp_as_res[1]
-
- if not self.async_manager:
- #cleanup tha database firstly
- purge_old_jobs()
- self.async_manager = AsyncResultManager()
- self.async_manager.refresh_list()
+ except Exception,e:
+ flash("We got some error while trying to send command for %s.%s.%s"%(module,minion,method))
+ return dict()
#TODO reformat that returning string to be more elegant to display :)
return str(result)
@@ -339,7 +408,12 @@ class Funcweb(object):
self.func_cache['methods']=None
#i assume that they are long enough so dont poll here
- result_id = getattr(getattr(fc,module),method)()
+ try:
+ result_id = getattr(getattr(fc,module),method)()
+ except Exception,e:
+ flash("Error when executing link command for %s.%s.%s"%(minion,module,method))
+ return dict()
+
result = "".join(["The id for current id is :",str(result_id)," You will be notified when there is some change about that command !"])
return dict(result=str(result))
@@ -370,7 +444,7 @@ class Funcweb(object):
return dict(changed = changed,changes = changes)
- @expose(template="funcweb.templates.result")
+ @expose(format = "json")
@identity.require(identity.not_anonymous())
def check_job_status(self,job_id):
"""
@@ -392,11 +466,22 @@ class Funcweb(object):
else:
fc_async = self.func_cache['fc_async_obj']
-
- id_result = fc_async.job_status(job_id)
+
+ try:
+ id_result = fc_async.job_status(job_id)
+ #parse the comming data in a better looking way :)
+ from funcweb.result_handler import produce_res_rec
+ minion_result = produce_res_rec(id_result[1])
+ #print "The current minion_result is : ",minion_result
+ global_result = {'id':0,'item':[]}
+ global_result['item'].extend(minion_result)
+
+ except Exception,e:
+ flash("We encountered some error while getting the status for %s job id"%(job_id))
+ return dict()
#the final id_result
- return dict(result=id_result)
+ return dict(minion_result = global_result)
@expose(template="funcweb.templates.async_table")
@identity.require(identity.not_anonymous())
@@ -428,9 +513,128 @@ class Funcweb(object):
"""
identity.current.logout()
raise redirect("/")
+
+################################ Groups API methods here #############################
+ @expose(template="funcweb.templates.groups_main")
+ @identity.require(identity.not_anonymous())
+ def groups_main(self):
+ """
+ The main page of the groups
+ """
+ #a dummy object to let us to get the groups api
+ #we dont supply a new group file it will handle the default
+ minion_api = Minions("*")
+ groups = minion_api.group_class.get_group_names()
+ del minion_api
+ #result to the template please :)
+ return dict(groups = groups)
+
+ @expose(template="funcweb.templates.list_group")
+ @identity.require(identity.not_anonymous())
+ def add_new_group(self,group_name,submit):
+ """
+ Adding a new group
+ """
+ minion_api = Minions("*")
+ minion_api.group_class.add_group(group_name,save=True)
+ groups = minion_api.group_class.get_group_names()
+ del minion_api
+ return dict(groups = groups)
+
+ @expose(template="funcweb.templates.list_group")
+ @identity.require(identity.not_anonymous())
+ def remove_group(self,**kw):
+ """
+ Adding a new group
+ """
+ minion_api = Minions("*")
+ minion_api.group_class.remove_group(kw['group_name'],save=True)
+ groups = minion_api.group_class.get_group_names()
+ del minion_api
+ return dict(groups = groups)
+
+ @expose(template="funcweb.templates.group_minion")
+ @identity.require(identity.not_anonymous())
+ def list_host_by_group(self,group_name):
+ """
+ Get the hosts for the specified group_name
+ """
+ from copy import copy
+ copy_group_name = copy(group_name)
+ if not group_name.startswith('@'):
+ group_name = "".join(["@",group_name.strip()])
+
+ try:
+ minion_api = Minions("*")
+ hosts = minion_api.group_class.get_hosts_by_group_glob(group_name)
+ all_minions = minion_api.get_all_hosts()
+ del minion_api
+ except Exception,e:
+ flash("We encountered some error while getting host list for %s "%(copy_group_name))
+ return dict()
+
+ #store the current group_name in cache variable
+ self.group_name = copy_group_name
+ return dict(hosts = hosts,all_minions = all_minions,group_name = copy_group_name,submit_adress="/funcweb/filter_group_minions")
+
+ @expose(template="funcweb.templates.group_small")
+ @identity.require(identity.not_anonymous())
+ def add_minions_togroup(self,**kw):
+ """
+ Add or remove multiple minions to given group
+ """
+ #print "The dict value is : ",kw
+ minion_api = Minions("*")
+ hosts = []
+ if not kw.has_key('group_name') or not kw.has_key('action_name'):
+ return dict(hosts =hosts,group_name = None)
+
+ current_host_list = None
+
+ #if we are adding some hosts
+ if kw['action_name'] == "add":
+ if not kw.has_key('checkminion'):
+ return dict(hosts =hosts,group_name = kw['group_name'])
+ current_host_list = kw['checkminion']
+ else:#it is a remove action
+ if not kw.has_key('rmgroup'):
+ return dict(hosts =hosts,group_name = kw['group_name'])
+ current_host_list = kw['rmgroup']
+ #sanity checks
+ if type(current_host_list)!=list:
+ hosts.extend(current_host_list.split(","))
+ else:
+ hosts.extend(current_host_list)
+
+ if kw['action_name'] == "add":
+ minion_api.group_class.add_host_list(kw['group_name'],hosts,save = True)
+ else:#remove them
+ minion_api.group_class.remove_host_list(kw['group_name'],hosts,save = True)
+
+ from copy import copy
+ #we need that check because @ is a sign for group search
+ group_name = copy(kw['group_name'])
+ if not group_name.startswith('@'):
+ group_name = "".join(["@",group_name.strip()])
+
+ hosts = minion_api.group_class.get_hosts_by_group_glob(group_name)
+ return dict(hosts =hosts,group_name = kw['group_name'])
+
+ @expose(allow_json=True)
+ @identity.require(identity.not_anonymous())
+ def filter_group_minions(self,glob='*',submit=None):
+ """ Return a list of our minions that match a given glob """
+ #make the cache thing
+
+ minions = self.get_current_minion_list(glob)
+ if submit:
+ return dict(all_minions=minions,submit_adress="/funcweb/filter_group_minions",tg_template="funcweb.templates.minion_small",group_name= self.group_name)
+ else:
+ return str("Wrong way :)")
+############################# END of GROUPS API METHODS ############################
class Root(controllers.RootController):
@expose()
diff --git a/funcweb/funcweb/identity/pam.py b/funcweb/funcweb/identity/pam.py
index 87bc126..0e45353 100644
--- a/funcweb/funcweb/identity/pam.py
+++ b/funcweb/funcweb/identity/pam.py
@@ -14,6 +14,8 @@ __all__ = ['authenticate']
from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, pointer, sizeof
from ctypes import c_void_p, c_uint, c_char_p, c_char, c_int
+#funcweb specific part
+from funcweb.commands import PRODUCTION_ENV
LIBPAM = CDLL("libpam.so.0")
LIBC = CDLL("libc.so.6")
@@ -82,7 +84,7 @@ PAM_AUTHENTICATE = LIBPAM.pam_authenticate
PAM_AUTHENTICATE.restype = c_int
PAM_AUTHENTICATE.argtypes = [PamHandle, c_int]
-def authenticate(username, password, service='login'):
+def authenticate(username, password, service=None):
"""Returns True if the given username and password authenticate for the
given service. Returns False otherwise
@@ -92,6 +94,13 @@ def authenticate(username, password, service='login'):
``service``: the PAM service to authenticate against.
Defaults to 'login'"""
+ #we make that control because we dont want to install ti everytime on system
+ #while working on funcweb ...
+ if PRODUCTION_ENV:
+ service = "funcweb"
+ else:
+ service = "login"
+
@CONV_FUNC
def my_conv(n_messages, messages, p_response, app_data):
"""Simple conversation function that responds to any
diff --git a/funcweb/funcweb/result_handler.py b/funcweb/funcweb/result_handler.py
new file mode 100644
index 0000000..afd62f1
--- /dev/null
+++ b/funcweb/funcweb/result_handler.py
@@ -0,0 +1,125 @@
+global_max = 0
+def produce_res_rec(result_pack):
+ """
+ A beautiful recursive tree like hash producer
+ """
+ send_list = []
+ global global_max
+ #print "The pack is counter:",counter
+ #print "The pack is result_pack:",result_pack
+ #print "The pack is global_result:",global_result
+ #the final step of the execution
+ if type(result_pack) != list and type(result_pack) != dict:
+ global_max = global_max + 1
+ return {'id':global_max,'text':str(result_pack)}
+
+ elif type(result_pack) == list :
+ for result_list in result_pack:
+ if type(result_list) == list:
+ #if there is a new list then the new parent trick
+ global_max = global_max +1
+ tmp_parent = {}
+ tmp_parent['id'] = global_max
+ tmp_parent['text'] = 'leaf_result%s'%(global_max)
+
+ tmp_list_result = produce_res_rec(result_list)
+
+ if tmp_list_result and type(tmp_list_result) == list:
+ tmp_parent['item'] = []
+ tmp_parent['item'].extend(tmp_list_result)
+ elif tmp_list_result:
+ tmp_parent['item'] = []
+ tmp_parent['item'].append(tmp_list_result)
+ #appended to the parent
+ send_list.append(tmp_parent)
+
+ else:
+ tmp_list_result = produce_res_rec(result_list)
+ if type(tmp_list_result) == list:
+ send_list.extend(tmp_list_result)
+ else:
+ send_list.append(tmp_list_result)
+
+ elif type(result_pack) == dict :
+ for key_result,value_result in result_pack.iteritems():
+ #a new key added
+ global_max = global_max +1
+ tmp_parent = {}
+ tmp_parent ['id'] = global_max
+ tmp_parent ['text'] = str(key_result)
+
+ tmp_dict_res = produce_res_rec(value_result)
+
+ if tmp_dict_res and type(tmp_dict_res) == list :
+ tmp_parent ['item'] = []
+ tmp_parent['item'].extend(tmp_dict_res)
+ elif tmp_dict_res:
+ tmp_parent ['item'] = []
+ tmp_parent['item'].append(tmp_dict_res)
+
+ send_list.append(tmp_parent)
+
+ else: #shouldnt come here !
+ return {}
+
+ return send_list
+
+if __name__ == "__main__":
+ """
+
+
+ main_pack = {
+ 'minion':[["one","two"],["three","four"]]
+ }
+
+
+
+
+
+
+
+ main_pack = {
+
+ 'minion':{
+ 'result1':True,
+ 'result2':False
+ },
+ 'minion2':{
+ 'result3':True,
+ 'result4':False
+ },
+ 'minion3':{
+ 'result5':True,
+ 'result6':False
+ }
+
+
+ }
+ """
+
+ main_pack = {
+ 'minion1':[
+ {
+ 'res1':[['hey','hhhey'],['mey','mmmey']]
+ },
+ {
+ 'res2':['wey','dey']
+ }
+ ],
+ 'minion2':[
+ {
+ 'res3':['nums','mums']
+ },
+ {
+ 'res4':['wums','dums']
+ }
+ ]
+
+ }
+
+
+ final = produce_res_rec(main_pack)
+ print "The final pack is like that : "
+ print final
+
+
diff --git a/funcweb/funcweb/static/css/dhtmlxtree.css b/funcweb/funcweb/static/css/dhtmlxtree.css
new file mode 100644
index 0000000..b18efc5
--- /dev/null
+++ b/funcweb/funcweb/static/css/dhtmlxtree.css
@@ -0,0 +1,61 @@
+.defaultTreeTable{
+ margin : 0px;
+ padding : 0px;
+ border : 0px;
+}
+.containerTableStyle { overflow : auto; position:relative; top:0; font-size : 12px;}
+.containerTableStyleRTL span { direction: rtl; unicode-bidi: bidi-override; }
+.containerTableStyleRTL { direction: rtl; overflow : auto; position:relative; top:0; font-size : 12px;}
+.standartTreeRow{ font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; font-size : 12px; -moz-user-select: none; }
+.selectedTreeRow{ background-color : navy; color:white; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; font-size : 12px; -moz-user-select: none; }
+.dragAndDropRow{ background-color : navy; color:white; }
+.standartTreeRow_lor{ text-decoration:underline; background-color : #FFFFF0; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; font-size : 12px; -moz-user-select: none; }
+.selectedTreeRow_lor{ text-decoration:underline; background-color : navy; color:white; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; font-size : 12px; -moz-user-select: none; }
+
+.standartTreeImage{ width:18px; height:18px; overflow:hidden; border:0; padding:0; margin:0;
+font-size:1px; }
+.hiddenRow { width:1px; overflow:hidden; }
+.dragSpanDiv,.dragSpanDiv td{ font-size : 12px; background-color:white; }
+
+
+.selectionBox{
+background-color: #FFFFCC;
+}
+.selectionBar {
+ top:0;
+ background-color: Black;
+ position:absolute;
+ overflow:hidden;
+ height: 2px;
+ z-index : 11;
+}
+
+.intreeeditRow{
+ width:100%; font-size:8pt; height:16px; border:1px solid silver; padding:0; margin:0;
+ -moz-user-select: text;
+}
+.dhx_tree_textSign{
+ font-size:8pt;
+ font-family:monospace;
+ width:21px;
+ color:black;
+ padding:0px;
+ margin:0px;
+ cursor:pointer;
+ text-align: center;
+}
+.dhx_tree_opacity{
+ opacity:0;
+ -moz-opacity:0;
+ filter:alpha(opacity=0);
+}
+.dhx_bg_img_fix{
+width:18px;
+height:18px;
+background-repeat: no-repeat;
+background-position: center;
+background-position-x: center;
+background-position-y: center;
+}
+
+
diff --git a/funcweb/funcweb/static/css/groupscss.css b/funcweb/funcweb/static/css/groupscss.css
new file mode 100755
index 0000000..404b2bd
--- /dev/null
+++ b/funcweb/funcweb/static/css/groupscss.css
@@ -0,0 +1,207 @@
+@charset "utf-8";
+/* CSS Document */
+
+
+#addgroupbigbox {
+background-color:#f7f7f7;
+height: 100px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+#addgroup {
+height:50px;
+width:400px;
+margin-left:auto;
+margin-right:auto;
+margin-top: 2em;
+}
+#groupnametext {
+height:40px;
+width:50px;
+float:left;
+margin-right:10px;
+padding-top:2px;
+margin-left:2.2em;
+}
+#groupsbigbox {
+background-color:#f7f7f7;
+overflow: auto;
+max-height: 250px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+#groupstexts {
+float:left;
+margin-left: 4em;
+height:25px;
+max-width: 250px;
+margin-top: 2em;
+}
+
+#miniongroupsbigbox {
+background-color:#f7f7f7;
+min-height: 150px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+
+.addgroupbox {
+background-color: #FFFFFF;
+border: 2px solid #dddddd;
+width:200px;
+height:20px;
+float:left;
+}
+.removebtn {
+height:25px;
+width:25px;
+background-image: url(../images/removebtn.jpg);
+background-repeat:no-repeat;
+display:block;
+border: 0px;
+margin-top: 2.4em;
+float:left;
+}
+.removebtn:link {
+height:25px;
+width:25px;
+background-image:url(../images/removebtn.jpg);
+background-repeat:no-repeat;
+display:block;
+border: 0px;
+margin-top: 2.4em;
+float:left;
+}
+.removebtn:hover {
+height:25px;
+width:25px;
+background-image: url(../images/removebtnhover.jpg);
+background-repeat:no-repeat;
+display:block;
+border: 0px;
+margin-top: 2.4em;
+float:left;
+}
+
+.removegroupbtn {
+height:25px;
+width:25px;
+background-image:url(../images/groupremovebtn.jpg);
+background-repeat:no-repeat;
+display:block;
+border: 0px;
+}
+.removegroupbtn:link {
+height:25px;
+width:25px;
+background-image:url(../images/groupremovebtn.jpg);
+background-repeat:no-repeat;
+display:block;
+border: 0px;
+}
+.removegroupbtn:hover {
+height:25px;
+width:25px;
+background-image: url(../images/groupremovebtnhover.jpg);
+background-repeat:no-repeat;
+display:block;
+border: 0px;
+}
+
+#group {
+max-height: 400px;
+width: 40%;
+padding:10px;
+float:left;
+margin-left:35px;
+margin-right:35px;
+}
+#groupbox {
+background-color:#F1F5F6;
+border: 2px solid #dddddd;
+overflow: auto;
+max-height: 150px;
+margin-top: 2em;
+}
+#grouptextbox {
+max-width:100px;
+margin-bottom:15px;
+margin-top:10px;
+margin-left:190px;
+}
+#minions2 {
+max-height: 400px;
+width: 40%;
+padding:10px;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+#minions2box {
+background-color:#F1F5F6;
+border: 2px solid #dddddd;
+overflow: auto;
+max-height: 150px;
+margin-top: 2em;
+}
+#minionstextbox {
+margin-left:190px;
+max-width:250px;
+margin-bottom:15px;
+margin-top:10px;
+}
+#selectallbox {
+float:right;
+margin-top:10px;
+}
+#selectallgroupboxes {
+float:left;
+margin-top:10px;
+}
+.minionsandgroupsbluetext {
+font-family: Arial, Helvetica, sans-serif;
+font-size:18px;
+color: #5499d4;
+text-decoration:none;
+}
+
+#minion_glob_box {
+padding-right:175px;
+width: 80%;
+height: 50px;
+float:right;
+}
+
+.addnewgroupbtn {
+height:25px;
+width:80px;;
+background-image: url(../images/buttonadd.jpg);
+border: 0px;
+padding-bottom:5px;
+}
+.addnewgroupbtn:link {
+height:25px;
+width:80px;;
+background-image: url(../images/buttonadd.jpg);
+border: 0px;
+padding-bottom:5px;
+}
+.addnewgroupbtn:hover {
+height:25px;
+width:80px;;
+background-image: url(../images/button_overadd.jpg);
+border: 0px;
+padding-bottom:5px;
+} \ No newline at end of file
diff --git a/funcweb/funcweb/static/css/style.css b/funcweb/funcweb/static/css/style.css
index 15745c8..e621bbf 100644
--- a/funcweb/funcweb/static/css/style.css
+++ b/funcweb/funcweb/static/css/style.css
@@ -195,7 +195,7 @@ margin-right:30px;
background-color:#f1f5f6;
overflow: auto;
height: 300px;
-width: 900px;
+width: 85%;
margin-left: auto;
margin-right: auto;
margin-top: 2em;
@@ -355,14 +355,14 @@ margin-left:3em;
.runmethoddiv {
height:25px;
-width:113px;;
+width:113px;
background-image: url(../images/button2.jpg);
background-repeat:no-repeat;
border: 0px;
}
-.runmethoddiv:hover{
+.runmethoddiv:hover {
height:25px;
-width:113px;;
+width:113px;
background-image: url(../images/button2_hover.jpg);
background-repeat:no-repeat;
border: 0px;
@@ -384,7 +384,7 @@ margin-right:30px;
background-color:#f1f5f6;
overflow: auto;
min-height: 150px;
-width: 900px;
+width: 85%;
margin-left: auto;
margin-right: auto;
margin-top: 2em;
@@ -500,33 +500,33 @@ text-decoration:none;
}
-table
+#inwidgetbox table
{
border-collapse: collapse;
}
-table th
+#inwidgetbox table th
{
background: #DDDDDD;
}
-table th,table td
+#inwidgetbox table th,#inwidgetbox table td
{
border: 1px solid #000000;
padding: 0.6ex;
}
-p
+#inwidgetbox p
{
margin: 1ex 5ex 1ex 0;
}
-input, textarea, select
+#inwidgetbox input, #inwidgetbox textarea, #inwidgetbox select
{
border: #AAA 1px solid;
}
-input, textarea, option
+#inwidgetbox input, #inwidgetbox textarea, #inwidgetbox option
{
padding: 2px 5px 2px 5px;
}
diff --git a/funcweb/funcweb/static/images/button_overadd.jpg b/funcweb/funcweb/static/images/button_overadd.jpg
new file mode 100644
index 0000000..32d0e2d
--- /dev/null
+++ b/funcweb/funcweb/static/images/button_overadd.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/buttonadd.jpg b/funcweb/funcweb/static/images/buttonadd.jpg
new file mode 100644
index 0000000..5942919
--- /dev/null
+++ b/funcweb/funcweb/static/images/buttonadd.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/groupremovebtn.jpg b/funcweb/funcweb/static/images/groupremovebtn.jpg
new file mode 100644
index 0000000..03adf3f
--- /dev/null
+++ b/funcweb/funcweb/static/images/groupremovebtn.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/groupremovebtnhover.jpg b/funcweb/funcweb/static/images/groupremovebtnhover.jpg
new file mode 100644
index 0000000..4c57451
--- /dev/null
+++ b/funcweb/funcweb/static/images/groupremovebtnhover.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/blank.gif b/funcweb/funcweb/static/images/imgs/blank.gif
new file mode 100644
index 0000000..d7ae406
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/blank.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/but_cut.gif b/funcweb/funcweb/static/images/imgs/but_cut.gif
new file mode 100644
index 0000000..942bd18
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/but_cut.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/folderClosed.gif b/funcweb/funcweb/static/images/imgs/folderClosed.gif
new file mode 100644
index 0000000..1ebe3c9
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/folderClosed.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/folderOpen.gif b/funcweb/funcweb/static/images/imgs/folderOpen.gif
new file mode 100644
index 0000000..c193e86
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/folderOpen.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/iconCheckAll.gif b/funcweb/funcweb/static/images/imgs/iconCheckAll.gif
new file mode 100644
index 0000000..d908992
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/iconCheckAll.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/iconCheckDis.gif b/funcweb/funcweb/static/images/imgs/iconCheckDis.gif
new file mode 100644
index 0000000..6f0b1c7
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/iconCheckDis.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/iconCheckGray.gif b/funcweb/funcweb/static/images/imgs/iconCheckGray.gif
new file mode 100644
index 0000000..cb54c0a
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/iconCheckGray.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/iconUncheckAll.gif b/funcweb/funcweb/static/images/imgs/iconUncheckAll.gif
new file mode 100644
index 0000000..5e54ec5
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/iconUncheckAll.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/iconUncheckDis.gif b/funcweb/funcweb/static/images/imgs/iconUncheckDis.gif
new file mode 100644
index 0000000..eec88a7
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/iconUncheckDis.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/leaf.gif b/funcweb/funcweb/static/images/imgs/leaf.gif
new file mode 100644
index 0000000..1cf40f1
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/leaf.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line.gif b/funcweb/funcweb/static/images/imgs/line.gif
new file mode 100644
index 0000000..60f2ccb
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line1.gif b/funcweb/funcweb/static/images/imgs/line1.gif
new file mode 100644
index 0000000..60f2ccb
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line1.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line1_rtl.gif b/funcweb/funcweb/static/images/imgs/line1_rtl.gif
new file mode 100644
index 0000000..96db473
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line1_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line2.gif b/funcweb/funcweb/static/images/imgs/line2.gif
new file mode 100644
index 0000000..f2d7bdd
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line2.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line2_rtl.gif b/funcweb/funcweb/static/images/imgs/line2_rtl.gif
new file mode 100644
index 0000000..5e6c6fc
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line2_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line3.gif b/funcweb/funcweb/static/images/imgs/line3.gif
new file mode 100644
index 0000000..d718be2
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line3.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line3_rtl.gif b/funcweb/funcweb/static/images/imgs/line3_rtl.gif
new file mode 100644
index 0000000..df7f5d8
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line3_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line4.gif b/funcweb/funcweb/static/images/imgs/line4.gif
new file mode 100644
index 0000000..29285e5
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line4.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/line4_rtl.gif b/funcweb/funcweb/static/images/imgs/line4_rtl.gif
new file mode 100644
index 0000000..6c97452
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/line4_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/lock.gif b/funcweb/funcweb/static/images/imgs/lock.gif
new file mode 100644
index 0000000..1d06b0d
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/lock.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus.gif b/funcweb/funcweb/static/images/imgs/minus.gif
new file mode 100644
index 0000000..ef04a54
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus2.gif b/funcweb/funcweb/static/images/imgs/minus2.gif
new file mode 100644
index 0000000..0372294
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus2.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus2_rtl.gif b/funcweb/funcweb/static/images/imgs/minus2_rtl.gif
new file mode 100644
index 0000000..521c2bf
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus2_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus3.gif b/funcweb/funcweb/static/images/imgs/minus3.gif
new file mode 100644
index 0000000..d928af6
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus3.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus3_rtl.gif b/funcweb/funcweb/static/images/imgs/minus3_rtl.gif
new file mode 100644
index 0000000..837f7c3
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus3_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus4.gif b/funcweb/funcweb/static/images/imgs/minus4.gif
new file mode 100644
index 0000000..30bc7de
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus4.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus4_rtl.gif b/funcweb/funcweb/static/images/imgs/minus4_rtl.gif
new file mode 100644
index 0000000..6dd9fbe
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus4_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus5.gif b/funcweb/funcweb/static/images/imgs/minus5.gif
new file mode 100644
index 0000000..e2e30fc
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus5.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus5_rtl.gif b/funcweb/funcweb/static/images/imgs/minus5_rtl.gif
new file mode 100644
index 0000000..ae0885b
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus5_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/minus_ar.gif b/funcweb/funcweb/static/images/imgs/minus_ar.gif
new file mode 100644
index 0000000..4428ba1
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/minus_ar.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus.gif b/funcweb/funcweb/static/images/imgs/plus.gif
new file mode 100644
index 0000000..abb84bd
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus2.gif b/funcweb/funcweb/static/images/imgs/plus2.gif
new file mode 100644
index 0000000..ea2816e
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus2.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus2_rtl.gif b/funcweb/funcweb/static/images/imgs/plus2_rtl.gif
new file mode 100644
index 0000000..f1ba582
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus2_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus3.gif b/funcweb/funcweb/static/images/imgs/plus3.gif
new file mode 100644
index 0000000..cd6967e
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus3.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus3_rtl.gif b/funcweb/funcweb/static/images/imgs/plus3_rtl.gif
new file mode 100644
index 0000000..b8cad18
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus3_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus4.gif b/funcweb/funcweb/static/images/imgs/plus4.gif
new file mode 100644
index 0000000..185bd9b
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus4.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus4_rtl.gif b/funcweb/funcweb/static/images/imgs/plus4_rtl.gif
new file mode 100644
index 0000000..ce882e4
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus4_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus5.gif b/funcweb/funcweb/static/images/imgs/plus5.gif
new file mode 100644
index 0000000..72fe4e5
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus5.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus5_rtl.gif b/funcweb/funcweb/static/images/imgs/plus5_rtl.gif
new file mode 100644
index 0000000..15455b5
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus5_rtl.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/plus_ar.gif b/funcweb/funcweb/static/images/imgs/plus_ar.gif
new file mode 100644
index 0000000..d2fcaf0
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/plus_ar.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/radio_off.gif b/funcweb/funcweb/static/images/imgs/radio_off.gif
new file mode 100644
index 0000000..27dc5f9
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/radio_off.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/imgs/radio_on.gif b/funcweb/funcweb/static/images/imgs/radio_on.gif
new file mode 100644
index 0000000..efd74ee
--- /dev/null
+++ b/funcweb/funcweb/static/images/imgs/radio_on.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/removebtn.jpg b/funcweb/funcweb/static/images/removebtn.jpg
new file mode 100644
index 0000000..f790fc7
--- /dev/null
+++ b/funcweb/funcweb/static/images/removebtn.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/removebtnhover.jpg b/funcweb/funcweb/static/images/removebtnhover.jpg
new file mode 100644
index 0000000..eef98b8
--- /dev/null
+++ b/funcweb/funcweb/static/images/removebtnhover.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/javascript/ajax.js b/funcweb/funcweb/static/javascript/ajax.js
index b54ed7a..7ad3df1 100644
--- a/funcweb/funcweb/static/javascript/ajax.js
+++ b/funcweb/funcweb/static/javascript/ajax.js
@@ -24,8 +24,18 @@ function addDomAjaxREsult(){
function remoteFormRequest(form, target, options) {
var query = Array();
var contents = formContents(form);
- for (var j=0; j<contents[0].length; j++)
- query[contents[0][j]] = contents[1][j];
+ for (var j=0; j<contents[0].length; j++){
+ if(compare(target,'group_small')==0){
+ if(!query[contents[0][j]]){
+ query[contents[0][j]] = [];
+ }
+ //add that here
+ query[contents[0][j]].push(contents[1][j]);
+
+ }
+ else
+ query[contents[0][j]] = contents[1][j];
+ }
query["tg_random"] = new Date().getTime();
//makePOSTRequest(form.action, target, queryString(query));
remoteRequest(form, form.action, target, query, options);
@@ -76,7 +86,24 @@ function makePOSTRequest(source, url, target, parameters, options) {
}
if (http_request.status == 200) {
if(target) {
- target.innerHTML = http_request.responseText;
+ var is_error = true;
+ //some hacky olution to catch the python errors
+ try{
+ var check_error = evalJSON(http_request.responseText);
+ }
+ catch(e){
+ //There is no error in request
+ is_error = false;
+ }
+ if (is_error == true){
+ if (compare(check_error['fg_flash'],null)!=0)
+ connection_error(check_error['tg_flash']);
+ else
+ is_error = false;
+ }
+
+ if (is_error == false)
+ target.innerHTML = http_request.responseText;
}
//success
if (options['on_success']) {
@@ -86,9 +113,15 @@ function makePOSTRequest(source, url, target, parameters, options) {
//failure
if (options['on_failure']) {
eval(options['on_failure']);
- } else {
+ //it seems to be an expiration ...
+ } else if(http_request.status == 403){
+ alert('It seems that current session expired you should log in !');
+ window.location = window.location.href;
+ }
+ else {
alert('There was a problem with the request. Status('+http_request.status+')');
}
+
}
//complete
if (options['on_complete']) {
@@ -104,3 +137,61 @@ function makePOSTRequest(source, url, target, parameters, options) {
http_request.setRequestHeader("Connection", "close");
http_request.send(parameters);
}
+
+function glob_submit(form_element,target_dom){
+ /*
+ * Because it is a common function we have to move it here for better results
+ * form_element is what we submit and the target_dom is the place that will be replaced
+ */
+
+ before_action = null;
+ //sometimes we are not sure which dom to get so is that situation
+ if(compare(target_dom,'not_sure')==0)
+ target_dom = which_dom();
+
+ //if we are in the index page should to that
+ if (compare(target_dom,'minioncontent')==0){
+ before_action = "hideElement(getElement('resultcontent'));hideElement(getElement('widgetcontent'));hideElement(getElement('methotdscontent'));hideElement(getElement('modulescontent'));";
+ }
+ else if(compare(target_dom,'groupscontent')==0){
+ before_action = "hideElement(getElement('miniongroupcontents'));";
+ }
+
+ form_result = remoteFormRequest(form_element,target_dom, {
+ 'loading': null,
+ 'confirm': null,
+ 'after':null,
+ 'on_complete':null,
+ 'loaded':null,
+ 'on_failure':null,
+ 'on_success':null,
+ 'before':before_action
+ }
+ );
+
+ return form_result;
+}
+
+function which_dom(){
+ /*
+ * We use the glob submit in lots of places so we should
+ * know where we are actually so that method will handle that
+ */
+
+ //that is for index.html
+ dom_result = getElement('minioncontent');
+ if (dom_result != null){
+ //alert("Im giving back the minioncontent");
+ return 'minioncontent';
+
+ }
+
+ //it is for groups_main.html
+ dom_result = getElement('minion_small');
+ //will change it later
+ if (dom_result != null){
+ return 'minion_small';
+ }
+
+ return dom_result;
+}
diff --git a/funcweb/funcweb/static/javascript/async_tools.js b/funcweb/funcweb/static/javascript/async_tools.js
index f96ebd2..98169fa 100644
--- a/funcweb/funcweb/static/javascript/async_tools.js
+++ b/funcweb/funcweb/static/javascript/async_tools.js
@@ -5,7 +5,8 @@ function poll_async_changes(result){
*/
//runs on the index page and polls the server side if there is new
- //change in the async db
+ //change in the async db
+ //alert(repr(result));
if (result['changed']==true){
//alert('Check it ');
var the_change_msg = "We have some async changes : ";
@@ -27,9 +28,14 @@ function check_async_change(){
}
));
d.addCallback(poll_async_changes);
+ d.addErrback(poll_error);
}
function poll_error(error){
- alert("Some error in xmlHttpRequest check your connection : ");
+ var error_msg = "Async Error : probably you have shut down your server or your session has expired try to REFRESH and check your connection !";
+ var error_div = getElement("globalerror");
+ if (error_div != null){
+ error_div.innerHTML = error_msg;
+ }
}
diff --git a/funcweb/funcweb/static/javascript/dhtmlxcommon.js b/funcweb/funcweb/static/javascript/dhtmlxcommon.js
new file mode 100644
index 0000000..34def09
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/dhtmlxcommon.js
@@ -0,0 +1,643 @@
+//v.1.6 build 80512
+
+/*
+Copyright DHTMLX LTD. http://www.dhtmlx.com
+You allowed to use this component or parts of it under GPL terms
+To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
+*/
+ /**
+ * @desc: xmlLoader object
+ * @type: private
+ * @param: funcObject - xml parser function
+ * @param: object - jsControl object
+ * @param: async - sync/async mode (async by default)
+ * @param: rSeed - enable/disable random seed ( prevent IE caching)
+ * @topic: 0
+ */
+function dtmlXMLLoaderObject(funcObject, dhtmlObject,async,rSeed){
+ this.xmlDoc="";
+
+ if (typeof(async) != "undefined")
+ this.async = async;
+ else this.async = true;
+
+ this.onloadAction=funcObject||null;
+ this.mainObject=dhtmlObject||null;
+ this.waitCall=null;
+ this.rSeed=rSeed||false;
+ return this;
+};
+ /**
+ * @desc: xml loading handler
+ * @type: private
+ * @param: dtmlObject - xmlLoader object
+ * @topic: 0
+ */
+ dtmlXMLLoaderObject.prototype.waitLoadFunction=function(dhtmlObject){
+ var once=true;
+ this.check=function (){
+ if ((dhtmlObject)&&(dhtmlObject.onloadAction!=null)){
+ if ((!dhtmlObject.xmlDoc.readyState)||(dhtmlObject.xmlDoc.readyState == 4)){
+ if (!once) return; once=false; //IE 5 fix
+ dhtmlObject.onloadAction(dhtmlObject.mainObject,null,null,null,dhtmlObject);
+ if (dhtmlObject.waitCall) { dhtmlObject.waitCall(); dhtmlObject.waitCall=null; }
+ }
+ }
+ };
+ return this.check;
+ };
+
+ /**
+ * @desc: return XML top node
+ * @param: tagName - top XML node tag name (not used in IE, required for Safari and Mozilla)
+ * @type: private
+ * @returns: top XML node
+ * @topic: 0
+ */
+ dtmlXMLLoaderObject.prototype.getXMLTopNode=function(tagName,oldObj){
+ if (this.xmlDoc.responseXML) {
+ var temp=this.xmlDoc.responseXML.getElementsByTagName(tagName);
+ var z=temp[0];
+ }else
+ var z=this.xmlDoc.documentElement;
+ if (z){
+ this._retry=false;
+ return z;
+ }
+
+ if ((_isIE)&&(!this._retry)){
+ //fall back to MS.XMLDOM
+ var xmlString=this.xmlDoc.responseText;
+ var oldObj=this.xmlDoc;
+ this._retry=true;
+ this.xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ this.xmlDoc.async=false;
+ this.xmlDoc["loadXM"+"L"](xmlString);
+
+ return this.getXMLTopNode(tagName,oldObj);
+ }
+ dhtmlxError.throwError("LoadXML","Incorrect XML",[(oldObj||this.xmlDoc),this.mainObject]);
+ return document.createElement("DIV");
+ };
+
+ /**
+ * @desc: load XML from string
+ * @type: private
+ * @param: xmlString - xml string
+ * @topic: 0
+ */
+ dtmlXMLLoaderObject.prototype.loadXMLString=function(xmlString){
+ {
+ try
+ {
+ var parser = new DOMParser();
+ this.xmlDoc = parser.parseFromString(xmlString,"text/xml");
+ }
+ catch(e){
+ this.xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ this.xmlDoc.async=this.async;
+ this.xmlDoc["loadXM"+"L"](xmlString);
+ }
+ }
+
+ this.onloadAction(this.mainObject,null,null,null,this);
+ if (this.waitCall) { this.waitCall(); this.waitCall=null; }
+ }
+ /**
+ * @desc: load XML
+ * @type: private
+ * @param: filePath - xml file path
+ * @param: postMode - send POST request
+ * @param: postVars - list of vars for post request
+ * @topic: 0
+ */
+ dtmlXMLLoaderObject.prototype.loadXML=function(filePath,postMode,postVars,rpc){
+ if (this.rSeed) filePath+=((filePath.indexOf("?")!=-1)?"&":"?")+"a_dhx_rSeed="+(new Date()).valueOf();
+ this.filePath=filePath;
+
+ if ((!_isIE)&&(window.XMLHttpRequest))
+ this.xmlDoc = new XMLHttpRequest();
+ else{
+
+ if (document.implementation && document.implementation.createDocument)
+ {
+ this.xmlDoc = document.implementation.createDocument("", "", null);
+ this.xmlDoc.onload = new this.waitLoadFunction(this);
+ this.xmlDoc.load(filePath);
+ return;
+ }
+ else
+ this.xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+
+
+ if (this.async)
+ this.xmlDoc.onreadystatechange=new this.waitLoadFunction(this);
+ this.xmlDoc.open(postMode?"POST":"GET",filePath,this.async);
+ if (rpc){
+ this.xmlDoc.setRequestHeader("User-Agent", "dhtmlxRPC v0.1 (" + navigator.userAgent + ")");
+ this.xmlDoc.setRequestHeader("Content-type", "text/xml");
+ } else
+ if (postMode) this.xmlDoc.setRequestHeader('Content-type','application/x-www-form-urlencoded');
+ this.xmlDoc.send(null||postVars);
+
+ if (!this.async) (new this.waitLoadFunction(this))();
+
+
+ };
+ /**
+ * @desc: destructor, cleans used memory
+ * @type: private
+ * @topic: 0
+ */
+ dtmlXMLLoaderObject.prototype.destructor=function(){
+ this.onloadAction=null;
+ this.mainObject=null;
+ this.xmlDoc=null;
+ return null;
+ }
+
+ /**
+ * @desc: Call wrapper
+ * @type: private
+ * @param: funcObject - action handler
+ * @param: dhtmlObject - user data
+ * @returns: function handler
+ * @topic: 0
+ */
+function callerFunction(funcObject,dhtmlObject){
+ this.handler=function(e){
+ if (!e) e=window.event;
+ funcObject(e,dhtmlObject);
+ return true;
+ };
+ return this.handler;
+};
+
+ /**
+ * @desc: Calculate absolute position of html object
+ * @type: private
+ * @param: htmlObject - html object
+ * @topic: 0
+ */
+function getAbsoluteLeft(htmlObject){
+ var xPos = htmlObject.offsetLeft;
+ var temp = htmlObject.offsetParent;
+ while (temp != null) {
+ xPos += temp.offsetLeft;
+ temp = temp.offsetParent;
+ }
+ return xPos;
+ }
+ /**
+ * @desc: Calculate absolute position of html object
+ * @type: private
+ * @param: htmlObject - html object
+ * @topic: 0
+ */
+function getAbsoluteTop(htmlObject) {
+ var yPos = htmlObject.offsetTop;
+ var temp = htmlObject.offsetParent;
+ while (temp != null) {
+ yPos += temp.offsetTop;
+ temp = temp.offsetParent;
+ }
+ return yPos;
+ }
+
+
+/**
+* @desc: Convert string to it boolean representation
+* @type: private
+* @param: inputString - string for covertion
+* @topic: 0
+*/
+function convertStringToBoolean(inputString){ if (typeof(inputString)=="string") inputString=inputString.toLowerCase();
+ switch(inputString){
+ case "1":
+ case "true":
+ case "yes":
+ case "y":
+ case 1:
+ case true:
+ return true;
+ break;
+ default: return false;
+ }
+}
+
+/**
+* @desc: find out what symbol to use as url param delimiters in further params
+* @type: private
+* @param: str - current url string
+* @topic: 0
+*/
+function getUrlSymbol(str){
+ if(str.indexOf("?")!=-1)
+ return "&"
+ else
+ return "?"
+ }
+
+
+function dhtmlDragAndDropObject(){
+ if (window.dhtmlDragAndDrop) return window.dhtmlDragAndDrop;
+ this.lastLanding=0;
+ this.dragNode=0;
+ this.dragStartNode=0;
+ this.dragStartObject=0;
+ this.tempDOMU=null;
+ this.tempDOMM=null;
+ this.waitDrag=0;
+ window.dhtmlDragAndDrop=this;
+
+ return this;
+ };
+
+ dhtmlDragAndDropObject.prototype.removeDraggableItem=function(htmlNode){
+ htmlNode.onmousedown=null;
+ htmlNode.dragStarter=null;
+ htmlNode.dragLanding=null;
+ }
+ dhtmlDragAndDropObject.prototype.addDraggableItem=function(htmlNode,dhtmlObject){
+ htmlNode.onmousedown=this.preCreateDragCopy;
+ htmlNode.dragStarter=dhtmlObject;
+ this.addDragLanding(htmlNode,dhtmlObject);
+ }
+ dhtmlDragAndDropObject.prototype.addDragLanding=function(htmlNode,dhtmlObject){
+ htmlNode.dragLanding=dhtmlObject;
+ }
+ dhtmlDragAndDropObject.prototype.preCreateDragCopy=function(e)
+ {
+ if (e && (e||event).button==2) return;
+ if (window.dhtmlDragAndDrop.waitDrag) {
+ window.dhtmlDragAndDrop.waitDrag=0;
+ document.body.onmouseup=window.dhtmlDragAndDrop.tempDOMU;
+ document.body.onmousemove=window.dhtmlDragAndDrop.tempDOMM;
+ return false;
+ }
+
+ window.dhtmlDragAndDrop.waitDrag=1;
+ window.dhtmlDragAndDrop.tempDOMU=document.body.onmouseup;
+ window.dhtmlDragAndDrop.tempDOMM=document.body.onmousemove;
+ window.dhtmlDragAndDrop.dragStartNode=this;
+ window.dhtmlDragAndDrop.dragStartObject=this.dragStarter;
+ document.body.onmouseup=window.dhtmlDragAndDrop.preCreateDragCopy;
+ document.body.onmousemove=window.dhtmlDragAndDrop.callDrag;
+
+ if ((e)&&(e.preventDefault)) { e.preventDefault(); return false; }
+ return false;
+ };
+ dhtmlDragAndDropObject.prototype.callDrag=function(e){
+ if (!e) e=window.event;
+ dragger=window.dhtmlDragAndDrop;
+
+ if ((e.button==0)&&(_isIE)) return dragger.stopDrag();
+ if (!dragger.dragNode && dragger.waitDrag) {
+ dragger.dragNode=dragger.dragStartObject._createDragNode(dragger.dragStartNode,e);
+ if (!dragger.dragNode) return dragger.stopDrag();
+ dragger.gldragNode=dragger.dragNode;
+ document.body.appendChild(dragger.dragNode);
+ document.body.onmouseup=dragger.stopDrag;
+ dragger.waitDrag=0;
+ dragger.dragNode.pWindow=window;
+ dragger.initFrameRoute();
+ }
+
+
+ if (dragger.dragNode.parentNode!=window.document.body){
+ var grd=dragger.gldragNode;
+ if (dragger.gldragNode.old) grd=dragger.gldragNode.old;
+
+ //if (!document.all) dragger.calculateFramePosition();
+ grd.parentNode.removeChild(grd);
+ var oldBody=dragger.dragNode.pWindow;
+ // var oldp=dragger.dragNode.parentObject;
+ if (_isIE){
+ var div=document.createElement("Div");
+ div.innerHTML=dragger.dragNode.outerHTML;
+ dragger.dragNode=div.childNodes[0]; }
+ else dragger.dragNode=dragger.dragNode.cloneNode(true);
+
+ dragger.dragNode.pWindow=window;
+ // dragger.dragNode.parentObject=oldp;
+
+ dragger.gldragNode.old=dragger.dragNode;
+ document.body.appendChild(dragger.dragNode);
+ oldBody.dhtmlDragAndDrop.dragNode=dragger.dragNode;
+ }
+
+ dragger.dragNode.style.left=e.clientX+15+(dragger.fx?dragger.fx*(-1):0)+(document.body.scrollLeft||document.documentElement.scrollLeft)+"px";
+ dragger.dragNode.style.top=e.clientY+3+(dragger.fy?dragger.fy*(-1):0)+(document.body.scrollTop||document.documentElement.scrollTop)+"px";
+ if (!e.srcElement) var z=e.target; else z=e.srcElement;
+ dragger.checkLanding(z,e);
+ }
+
+ dhtmlDragAndDropObject.prototype.calculateFramePosition=function(n){
+ //this.fx = 0, this.fy = 0;
+ if (window.name) {
+ var el =parent.frames[window.name].frameElement.offsetParent;
+ var fx=0;
+ var fy=0;
+ while (el) { fx += el.offsetLeft; fy += el.offsetTop; el = el.offsetParent; }
+ if ((parent.dhtmlDragAndDrop)) { var ls=parent.dhtmlDragAndDrop.calculateFramePosition(1); fx+=ls.split('_')[0]*1; fy+=ls.split('_')[1]*1; }
+ if (n) return fx+"_"+fy;
+ else this.fx=fx; this.fy=fy;
+ }
+ return "0_0";
+ }
+ dhtmlDragAndDropObject.prototype.checkLanding=function(htmlObject,e){
+
+ if ((htmlObject)&&(htmlObject.dragLanding)) {
+ if (this.lastLanding)
+ this.lastLanding.dragLanding._dragOut(this.lastLanding);
+ this.lastLanding=htmlObject;
+ this.lastLanding=this.lastLanding.dragLanding._dragIn(this.lastLanding,this.dragStartNode,e.clientX, e.clientY,e);
+ this.lastLanding_scr=(_isIE?e.srcElement:e.target);
+ }
+ else {
+ if ((htmlObject)&&(htmlObject.tagName!="BODY")) this.checkLanding(htmlObject.parentNode,e);
+ else {
+ if (this.lastLanding) this.lastLanding.dragLanding._dragOut(this.lastLanding,e.clientX, e.clientY,e); this.lastLanding=0;
+ if (this._onNotFound) this._onNotFound();
+ }
+ }
+ }
+ dhtmlDragAndDropObject.prototype.stopDrag=function(e,mode){
+ dragger=window.dhtmlDragAndDrop;
+ if (!mode)
+ {
+ dragger.stopFrameRoute();
+ var temp=dragger.lastLanding;
+ dragger.lastLanding=null;
+ if (temp) temp.dragLanding._drag(dragger.dragStartNode,dragger.dragStartObject,temp,(_isIE?event.srcElement:e.target));
+ }
+ dragger.lastLanding=null;
+ if ((dragger.dragNode)&&(dragger.dragNode.parentNode==document.body)) dragger.dragNode.parentNode.removeChild(dragger.dragNode);
+ dragger.dragNode=0;
+ dragger.gldragNode=0;
+ dragger.fx=0;
+ dragger.fy=0;
+ dragger.dragStartNode=0;
+ dragger.dragStartObject=0;
+ document.body.onmouseup=dragger.tempDOMU;
+ document.body.onmousemove=dragger.tempDOMM;
+ dragger.tempDOMU=null;
+ dragger.tempDOMM=null;
+ dragger.waitDrag=0;
+ }
+
+ dhtmlDragAndDropObject.prototype.stopFrameRoute=function(win){
+ if (win)
+ window.dhtmlDragAndDrop.stopDrag(1,1);
+
+ for (var i=0; i<window.frames.length; i++)
+ if ((window.frames[i]!=win)&&(window.frames[i].dhtmlDragAndDrop))
+ window.frames[i].dhtmlDragAndDrop.stopFrameRoute(window);
+ if ((parent.dhtmlDragAndDrop)&&(parent!=window)&&(parent!=win))
+ parent.dhtmlDragAndDrop.stopFrameRoute(window);
+ }
+ dhtmlDragAndDropObject.prototype.initFrameRoute=function(win,mode){
+ if (win) {
+
+
+ window.dhtmlDragAndDrop.preCreateDragCopy();
+ window.dhtmlDragAndDrop.dragStartNode=win.dhtmlDragAndDrop.dragStartNode;
+ window.dhtmlDragAndDrop.dragStartObject=win.dhtmlDragAndDrop.dragStartObject;
+ window.dhtmlDragAndDrop.dragNode=win.dhtmlDragAndDrop.dragNode;
+ window.dhtmlDragAndDrop.gldragNode=win.dhtmlDragAndDrop.dragNode;
+ window.document.body.onmouseup=window.dhtmlDragAndDrop.stopDrag;
+ window.waitDrag=0;
+ if (((!_isIE)&&(mode))&&((!_isFF)||(_FFrv<1.8)))
+ window.dhtmlDragAndDrop.calculateFramePosition();
+ }
+ if ((parent.dhtmlDragAndDrop)&&(parent!=window)&&(parent!=win))
+ parent.dhtmlDragAndDrop.initFrameRoute(window);
+ for (var i=0; i<window.frames.length; i++)
+ if ((window.frames[i]!=win)&&(window.frames[i].dhtmlDragAndDrop))
+ window.frames[i].dhtmlDragAndDrop.initFrameRoute(window,((!win||mode)?1:0));
+
+ }
+
+var _isFF=false; var _isIE=false; var _isOpera=false; var _isKHTML=false; var _isMacOS=false;
+
+if (navigator.userAgent.indexOf('Macintosh') != -1) _isMacOS=true;
+if ((navigator.userAgent.indexOf('Safari') != -1)||(navigator.userAgent.indexOf('Konqueror')!= -1)){
+ var _KHTMLrv=parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Safari')+7,5));
+ if (_KHTMLrv > 525){ //mimic FF behavior for Safari 3.1+
+
+ _isFF=true;
+ var _FFrv=1.9;
+ } else
+ _isKHTML=true;
+}
+else if (navigator.userAgent.indexOf('Opera') != -1){
+ _isOpera=true;
+ _OperaRv=parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Opera')+6,3));
+ }
+else if(navigator.appName.indexOf("Microsoft")!=-1)
+ _isIE=true;
+else {
+ _isFF=true;
+ var _FFrv=parseFloat(navigator.userAgent.split("rv:")[1])
+ }
+
+//deprecated, use global constant instead
+//determines if current browser is IE
+function isIE(){
+ if(navigator.appName.indexOf("Microsoft")!=-1)
+ if (navigator.userAgent.indexOf('Opera') == -1)
+ return true;
+ return false;
+}
+
+//multibrowser Xpath processor
+dtmlXMLLoaderObject.prototype.doXPath = function(xpathExp,docObj,namespace,result_type){
+ if ((_isKHTML)) return this.doXPathOpera(xpathExp,docObj);
+ if(_isIE){//IE
+ if(!docObj)
+ if(!this.xmlDoc.nodeName)
+ docObj = this.xmlDoc.responseXML
+ else
+ docObj = this.xmlDoc;
+ if (!docObj) dhtmlxError.throwError("LoadXML","Incorrect XML",[(docObj||this.xmlDoc),this.mainObject]);
+
+ if(namespace!=null)
+ docObj.setProperty("SelectionNamespaces","xmlns:xsl='"+namespace+"'");//
+ if(result_type=='single'){
+ return docObj.selectSingleNode(xpathExp);
+ }else{
+ return docObj.selectNodes(xpathExp)||new Array(0);
+ }
+ }else{//Mozilla
+ var nodeObj = docObj;
+ if(!docObj){
+ if(!this.xmlDoc.nodeName){
+ docObj = this.xmlDoc.responseXML
+ }else{
+ docObj = this.xmlDoc;
+ }
+ }
+
+ if (!docObj) dhtmlxError.throwError("LoadXML","Incorrect XML",[(docObj||this.xmlDoc),this.mainObject]);
+ if(docObj.nodeName.indexOf("document")!=-1){
+ nodeObj = docObj;
+ }else{
+ nodeObj = docObj;
+ docObj = docObj.ownerDocument;
+
+ }
+ var retType = XPathResult.ANY_TYPE;
+ if(result_type=='single')
+ retType = XPathResult.FIRST_ORDERED_NODE_TYPE
+ var rowsCol = new Array();
+ var col = docObj.evaluate(xpathExp, nodeObj, function(pref){return namespace}, retType,null);
+ if(retType == XPathResult.FIRST_ORDERED_NODE_TYPE){
+ return col.singleNodeValue ;
+ }
+ var thisColMemb = col.iterateNext();
+ while (thisColMemb) {
+ rowsCol[rowsCol.length] = thisColMemb;
+ thisColMemb = col.iterateNext();
+ }
+ return rowsCol;
+ }
+}
+
+
+function _dhtmlxError(type,name,params){
+ if (!this.catches)
+ this.catches=new Array();
+
+ return this;
+}
+
+_dhtmlxError.prototype.catchError=function(type,func_name){
+ this.catches[type]=func_name;
+}
+_dhtmlxError.prototype.throwError=function(type,name,params){
+ if (this.catches[type]) return this.catches[type](type,name,params);
+ if (this.catches["ALL"]) return this.catches["ALL"](type,name,params);
+ alert("Error type: " + arguments[0]+"\nDescription: " + arguments[1] );
+ return null;
+}
+
+window.dhtmlxError=new _dhtmlxError();
+
+
+//opera fake, while 9.0 not released
+//multibrowser Xpath processor
+dtmlXMLLoaderObject.prototype.doXPathOpera = function(xpathExp,docObj){
+ //this is fake for Opera
+ var z=xpathExp.replace(/[\/]+/gi,"/").split('/');
+ var obj=null;
+ var i=1;
+
+ if (!z.length) return [];
+ if (z[0]==".")
+ obj=[docObj];
+ else if (z[0]=="")
+ {
+ obj=(this.xmlDoc.responseXML||this.xmlDoc).getElementsByTagName(z[i].replace(/\[[^\]]*\]/g,""));
+ i++;
+ }
+ else return [];
+
+ for (i; i<z.length; i++)
+ obj=this._getAllNamedChilds(obj,z[i]);
+
+ if (z[i-1].indexOf("[")!=-1)
+ obj=this._filterXPath(obj,z[i-1]);
+ return obj;
+}
+
+dtmlXMLLoaderObject.prototype._filterXPath = function(a,b){
+ var c=new Array();
+ var b=b.replace(/[^\[]*\[\@/g,"").replace(/[\[\]\@]*/g,"");
+ for (var i=0; i<a.length; i++)
+ if (a[i].getAttribute(b))
+ c[c.length]=a[i];
+
+ return c;
+}
+dtmlXMLLoaderObject.prototype._getAllNamedChilds = function(a,b){
+ var c=new Array();
+ if (_isKHTML) b=b.toUpperCase();
+ for (var i=0; i<a.length; i++)
+ for (var j=0; j<a[i].childNodes.length; j++){
+ if (_isKHTML) {
+ if (a[i].childNodes[j].tagName && a[i].childNodes[j].tagName.toUpperCase()==b)
+ c[c.length]=a[i].childNodes[j];
+ }
+ else
+ if (a[i].childNodes[j].tagName==b) c[c.length]=a[i].childNodes[j];
+ }
+
+ return c;
+}
+
+function dhtmlXHeir(a,b){
+ for (var c in b)
+ if (typeof(b[c])=="function") a[c]=b[c];
+ return a;
+}
+function dhtmlxEvent(el,event,handler){
+ if (el.addEventListener)
+ el.addEventListener(event,handler,false);
+ else if (el.attachEvent)
+ el.attachEvent("on"+event,handler);
+}
+
+//============= XSL Extension ===================================
+
+dtmlXMLLoaderObject.prototype.xslDoc = null;
+dtmlXMLLoaderObject.prototype.setXSLParamValue = function(paramName,paramValue,xslDoc){
+ if(!xslDoc)
+ xslDoc = this.xslDoc
+ if(xslDoc.responseXML)
+ xslDoc = xslDoc.responseXML;
+ var item = this.doXPath("/xsl:stylesheet/xsl:variable[@name='"+paramName+"']",xslDoc,"http:/\/www.w3.org/1999/XSL/Transform","single");
+ if(item!=null)
+ item.firstChild.nodeValue=paramValue
+
+}
+dtmlXMLLoaderObject.prototype.doXSLTransToObject = function(xslDoc,xmlDoc)
+{
+ if(!xslDoc)
+ xslDoc = this.xslDoc;
+ if(xslDoc.responseXML)
+ xslDoc = xslDoc.responseXML
+
+ if(!xmlDoc)
+ xmlDoc = this.xmlDoc;
+ if(xmlDoc.responseXML)
+ xmlDoc = xmlDoc.responseXML
+
+ //MOzilla
+ if(!isIE()){
+ if(!this.XSLProcessor){
+ this.XSLProcessor = new XSLTProcessor();
+ this.XSLProcessor.importStylesheet(xslDoc);
+ }
+ var result = this.XSLProcessor.transformToDocument(xmlDoc);
+ }else{
+ var result = new ActiveXObject("Msxml2.DOMDocument.3.0");
+ xmlDoc.transformNodeToObject(xslDoc,result);
+ }
+ return result;
+}
+
+dtmlXMLLoaderObject.prototype.doXSLTransToString = function(xslDoc,xmlDoc)
+{
+ return this.doSerialization(this.doXSLTransToObject(xslDoc,xmlDoc));
+}
+
+dtmlXMLLoaderObject.prototype.doSerialization = function(xmlDoc){
+ if(!isIE()){
+ var xmlSerializer = new XMLSerializer();
+ return xmlSerializer.serializeToString(xmlDoc);
+ }else
+ return xmlDoc.xml;
+}
+
+//(c)dhtmlx ltd. www.dhtmlx.com \ No newline at end of file
diff --git a/funcweb/funcweb/static/javascript/dhtmlxtree.js b/funcweb/funcweb/static/javascript/dhtmlxtree.js
new file mode 100644
index 0000000..9b0310e
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/dhtmlxtree.js
@@ -0,0 +1,3742 @@
+//v.1.6 build 80512
+
+/*
+Copyright DHTMLX LTD. http://www.dhtmlx.com
+You allowed to use this component or parts of it under GPL terms
+To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
+*/
+/*_TOPICS_
+@0:Initialization
+@1:Selection control
+@2:Add/delete
+@3:Private
+@4:Node/level control
+@5:Checkboxes/user data manipulation
+@6:Appearence control
+@7: Handlers
+*/
+
+function xmlPointer(data){
+ this.d=data;
+}
+xmlPointer.prototype={
+ text:function(){ if (!_isFF) return this.d.xml; var x = new XMLSerializer(); return x.serializeToString(this.d); },
+ get:function(name){return this.d.getAttribute(name); },
+ exists:function(){return !!this.d },
+ content:function(){return this.d.firstChild?this.d.firstChild.data:""; }, // <4k in FF
+ each:function(name,f,t,i){ var a=this.d.childNodes; var c=new xmlPointer(); if (a.length) for (i=i||0; i<a.length; i++) if (a[i].tagName==name) { c.d=a[i]; if(f.apply(t,[c,i])==-1) return; } },
+ get_all:function(){ var a={}; var b=this.d.attributes; for (var i=0; i<b.length; i++) a[b[i].name]=b[i].value; return a; },
+ sub:function(name){ var a=this.d.childNodes; var c=new xmlPointer(); if (a.length) for (var i=0; i<a.length; i++) if (a[i].tagName==name) { c.d=a[i]; return c; } },
+ up:function(name){ return new xmlPointer(this.d.parentNode); },
+ set:function(name,val){ this.d.setAttribute(name,val); },
+ clone:function(name){ return new xmlPointer(this.d); },
+ sub_exists:function(name){ var a=this.d.childNodes; if (a.length) for (var i=0; i<a.length; i++) if (a[i].tagName==name) return true; return false; },
+ through:function(name,rule,v,f,t){ var a=this.d.childNodes; if (a.length) for (var i=0; i<a.length; i++) { if (a[i].tagName==name && a[i].getAttribute(rule)!=null && a[i].getAttribute(rule)!="" && (!v || a[i].getAttribute(rule)==v )) { var c=new xmlPointer(a[i]); f.apply(t,[c,i]); } var w=this.d; this.d=a[i]; this.through(name,rule,v,f,t); this.d=w; } }
+}
+
+
+
+/**
+* @desc: tree constructor
+* @param: htmlObject - parent html object or id of parent html object
+* @param: width - tree width
+* @param: height - tree height
+* @param: rootId - id of virtual root node (same as tree node id attribute in xml)
+* @type: public
+* @topic: 0
+*/
+function dhtmlXTreeObject(htmlObject, width, height, rootId){
+ if (_isIE) try { document.execCommand("BackgroundImageCache", false, true); } catch (e){}
+ if (typeof(htmlObject)!="object")
+ this.parentObject=document.getElementById(htmlObject);
+ else
+ this.parentObject=htmlObject;
+
+ this._itim_dg=true;
+ this.dlmtr=",";
+ this.dropLower=false;
+ this.enableIEImageFix();
+
+ this.xmlstate=0;
+ this.mytype="tree";
+ this.smcheck=true; //smart checkboxes
+ this.width=width;
+ this.height=height;
+ this.rootId=rootId;
+ this.childCalc=null;
+ this.def_img_x="18px";
+ this.def_img_y="18px";
+ this.def_line_img_x="18px";
+ this.def_line_img_y="18px";
+
+ this._dragged=new Array();
+ this._selected=new Array();
+
+ this.style_pointer="pointer";
+ if (_isIE) this.style_pointer="hand";
+
+ this._aimgs=true;
+ this.htmlcA=" [";
+ this.htmlcB="]";
+ this.lWin=window;
+ this.cMenu=0;
+ this.mlitems=0;
+ this.dadmode=0;
+ this.slowParse=false;
+ this.autoScroll=true;
+ this.hfMode=0;
+ this.nodeCut=new Array();
+ this.XMLsource=0;
+ this.XMLloadingWarning=0;
+ this._idpull={};
+ this._pullSize=0;
+ this.treeLinesOn=true;
+ this.tscheck=false;
+ this.timgen=true;
+ this.dpcpy=false;
+ this._ld_id=null;
+ this._oie_onXLE=[];
+ this.imPath="treeGfx/";
+ this.checkArray=new Array("iconUncheckAll.gif","iconCheckAll.gif","iconCheckGray.gif","iconUncheckDis.gif","iconCheckDis.gif","iconCheckDis.gif");
+ this.radioArray=new Array("radio_off.gif","radio_on.gif","radio_on.gif","radio_off.gif","radio_on.gif","radio_on.gif");
+
+ this.lineArray=new Array("line2.gif","line3.gif","line4.gif","blank.gif","blank.gif","line1.gif");
+ this.minusArray=new Array("minus2.gif","minus3.gif","minus4.gif","minus.gif","minus5.gif");
+ this.plusArray=new Array("plus2.gif","plus3.gif","plus4.gif","plus.gif","plus5.gif");
+ this.imageArray=new Array("leaf.gif","folderOpen.gif","folderClosed.gif");
+ this.cutImg= new Array(0,0,0);
+ this.cutImage="but_cut.gif";
+
+ this.dragger= new dhtmlDragAndDropObject();
+//create root
+ this.htmlNode=new dhtmlXTreeItemObject(this.rootId,"",0,this);
+ this.htmlNode.htmlNode.childNodes[0].childNodes[0].style.display="none";
+ this.htmlNode.htmlNode.childNodes[0].childNodes[0].childNodes[0].className="hiddenRow";
+//init tree structures
+ this.allTree=this._createSelf();
+ this.allTree.appendChild(this.htmlNode.htmlNode);
+ if(_isFF) this.allTree.childNodes[0].width="100%";
+
+ var self=this;
+ this.allTree.onselectstart=new Function("return false;");
+ if (_isMacOS)
+ this.allTree.oncontextmenu = function(e){ return self._doContClick(e||window.event); };
+ this.allTree.onmousedown = function(e){ return self._doContClick(e||window.event); };
+
+ this.XMLLoader=new dtmlXMLLoaderObject(this._parseXMLTree,this,true,this.no_cashe);
+ if (_isIE) this.preventIECashing(true);
+
+
+
+
+ if (window.addEventListener) window.addEventListener("unload",function(){try{ self.destructor(); } catch(e){}},false);
+ if (window.attachEvent) window.attachEvent("onunload",function(){ try{ self.destructor(); } catch(e){}});
+
+ this.dhx_Event();
+ this._onEventSet={onMouseIn:function(){this.ehlt=true;},onMouseOut:function(){this.ehlt=true;},onSelect:function(){this._onSSCF=true;}}
+
+ return this;
+};
+
+
+/**
+* @desc: set default data transfer mode
+* @param: mode - data mode (json,xml,csv)
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.setDataMode=function(mode){
+ this._datamode=mode;
+}
+
+
+
+dhtmlXTreeObject.prototype._doContClick=function(ev){
+ if (ev.button!=2) {
+ if(this._acMenu) this.cMenu._contextEnd();
+ return true;
+ }
+
+ var el=(_isIE?ev.srcElement:ev.target);
+ while ((el)&&(el.tagName!="BODY")) {
+ if (el.parentObject) break;
+ el=el.parentNode;
+ }
+
+ if ((!el)||(!el.parentObject)) return true;
+
+ var obj=el.parentObject;
+ this._acMenu=(obj.cMenu||this.cMenu);
+ if (this._acMenu){
+ el.contextMenuId=obj.id;
+ el.contextMenu=this._acMenu;
+ el.a=this._acMenu._contextStart;
+ if (_isIE)
+ ev.srcElement.oncontextmenu = function(){ event.cancelBubble=true; return false; };
+ el.a(el,ev); el.a=null;
+ ev.cancelBubble=true;
+ return false;
+ }
+ return true;
+}
+
+
+/**
+* @desc: replace IMG tag with background images - solve problem with IE image caching , not works for IE6 SP1
+* @param: mode - true/false - enable/disable fix
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.enableIEImageFix=function(mode){
+ if (!mode){
+
+ this._getImg=function(id){ return document.createElement((id==this.rootId)?"div":"img"); }
+ this._setSrc=function(a,b){ a.src=b; }
+ this._getSrc=function(a){ return a.src; }
+ } else {
+
+ this._getImg=function(){ var z=document.createElement("DIV"); z.innerHTML="&nbsp;"; z.className="dhx_bg_img_fix"; return z; }
+ this._setSrc=function(a,b){ a.style.backgroundImage="url("+b+")"; }
+ this._getSrc=function(a){ var z=a.style.backgroundImage; return z.substr(4,z.length-5); }
+ }
+}
+
+/**
+* @desc: deletes tree and clears memory
+* @type: public
+*/
+dhtmlXTreeObject.prototype.destructor=function(){
+ for (var a in this._idpull){
+ var z=this._idpull[a];
+ if (!z) continue;
+ z.parentObject=null;z.treeNod=null;z.childNodes=null;z.span=null;z.tr.nodem=null;z.tr=null;z.htmlNode.objBelong=null;z.htmlNode=null;
+ this._idpull[a]=null;
+ }
+ this.allTree.innerHTML="";
+ this.XMLLoader.destructor();
+ for(var a in this){
+ this[a]=null;
+ }
+}
+
+function cObject(){
+ return this;
+}
+cObject.prototype= new Object;
+cObject.prototype.clone = function () {
+ function _dummy(){};
+ _dummy.prototype=this;
+ return new _dummy();
+ }
+
+/**
+* @desc: tree node constructor
+* @param: itemId - node id
+* @param: itemText - node label
+* @param: parentObject - parent item object
+* @param: treeObject - tree object
+* @param: actionHandler - onclick event handler(optional)
+* @param: mode - do not show images
+* @type: private
+* @topic: 0
+*/
+function dhtmlXTreeItemObject(itemId,itemText,parentObject,treeObject,actionHandler,mode){
+ this.htmlNode="";
+ this.acolor="";
+ this.scolor="";
+ this.tr=0;
+ this.childsCount=0;
+ this.tempDOMM=0;
+ this.tempDOMU=0;
+ this.dragSpan=0;
+ this.dragMove=0;
+ this.span=0;
+ this.closeble=1;
+ this.childNodes=new Array();
+ this.userData=new cObject();
+
+
+ this.checkstate=0;
+ this.treeNod=treeObject;
+ this.label=itemText;
+ this.parentObject=parentObject;
+ this.actionHandler=actionHandler;
+ this.images=new Array(treeObject.imageArray[0],treeObject.imageArray[1],treeObject.imageArray[2]);
+
+
+ this.id=treeObject._globalIdStorageAdd(itemId,this);
+ if (this.treeNod.checkBoxOff ) this.htmlNode=this.treeNod._createItem(1,this,mode);
+ else this.htmlNode=this.treeNod._createItem(0,this,mode);
+
+ this.htmlNode.objBelong=this;
+ return this;
+ };
+
+
+/**
+* @desc: register node
+* @type: private
+* @param: itemId - node id
+* @param: itemObject - node object
+* @topic: 3
+*/
+ dhtmlXTreeObject.prototype._globalIdStorageAdd=function(itemId,itemObject){
+ if (this._globalIdStorageFind(itemId,1,1)) { itemId=itemId +"_"+(new Date()).valueOf(); return this._globalIdStorageAdd(itemId,itemObject); }
+ this._idpull[itemId]=itemObject;
+ this._pullSize++;
+ return itemId;
+ };
+
+/**
+* @desc: unregister node
+* @type: private
+* @param: itemId - node id
+* @topic: 3
+*/
+ dhtmlXTreeObject.prototype._globalIdStorageSub=function(itemId){
+ if (this._idpull[itemId]){
+ this._unselectItem(this._idpull[itemId]);
+ this._idpull[itemId]=null;
+ this._pullSize--;
+ }
+ if ((this._locker)&&(this._locker[itemId])) this._locker[itemId]=false;
+ };
+
+/**
+* @desc: return node object
+* @param: itemId - node id
+* @type: private
+* @topic: 3
+*/
+ dhtmlXTreeObject.prototype._globalIdStorageFind=function(itemId,skipXMLSearch,skipParsing,isreparse){
+ var z=this._idpull[itemId]
+ if (z){
+
+ return z;
+ }
+
+ return null;
+ };
+
+
+/**
+* @desc: escape string
+* @param: itemId - item ID
+* @type: private
+* @topic: 3
+*/
+ dhtmlXTreeObject.prototype._escape=function(str){
+ switch(this.utfesc){
+ case "none":
+ return str;
+ break;
+ case "utf8":
+ return encodeURI(str);
+ break;
+ default:
+ return escape(str);
+ break;
+ }
+ }
+
+
+
+/**
+* @desc: create and return new line in tree
+* @type: private
+* @param: htmlObject - parent Node object
+* @param: node - item object
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype._drawNewTr=function(htmlObject,node)
+ {
+ var tr =document.createElement('tr');
+ var td1=document.createElement('td');
+ var td2=document.createElement('td');
+ td1.appendChild(document.createTextNode(" "));
+ td2.colSpan=3;
+ td2.appendChild(htmlObject);
+ tr.appendChild(td1); tr.appendChild(td2);
+ return tr;
+ };
+/**
+* @desc: load tree from xml string
+* @type: public
+* @param: xmlString - XML string
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.loadXMLString=function(xmlString,afterCall){
+ var that=this;
+ if (!this.parsCount) this.callEvent("onXLS",[that,null]);
+ this.xmlstate=1;
+
+ if (afterCall) this.XMLLoader.waitCall=afterCall;
+ this.XMLLoader.loadXMLString(xmlString); };
+/**
+* @desc: load tree from xml file
+* @type: public
+* @param: file - link to XML file
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.loadXML=function(file,afterCall){
+ if (this._datamode && this._datamode!="xml") return this["load"+this._datamode.toUpperCase()](file,afterCall);
+ var that=this;
+ if (!this.parsCount) this.callEvent("onXLS",[that,this._ld_id]);
+ this._ld_id=null;
+ this.xmlstate=1;
+ this.XMLLoader=new dtmlXMLLoaderObject(this._parseXMLTree,this,true,this.no_cashe);
+
+ if (afterCall) this.XMLLoader.waitCall=afterCall;
+ this.XMLLoader.loadXML(file);
+ };
+/**
+* @desc: create new child node
+* @type: private
+* @param: parentObject - parent node object
+* @param: itemId - new node id
+* @param: itemText - new node text
+* @param: itemActionHandler - function fired on node select event
+* @param: image1 - image for node without children;
+* @param: image2 - image for closed node;
+* @param: image3 - image for opened node
+* @param: optionStr - string of otions
+* @param: childs - node childs flag (for dynamical trees) (optional)
+* @param: beforeNode - node, after which new node will be inserted (optional)
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype._attachChildNode=function(parentObject,itemId,itemText,itemActionHandler,image1,image2,image3,optionStr,childs,beforeNode,afterNode){
+
+ if (beforeNode && beforeNode.parentObject) parentObject=beforeNode.parentObject;
+ if (((parentObject.XMLload==0)&&(this.XMLsource))&&(!this.XMLloadingWarning))
+ {
+ parentObject.XMLload=1;
+ this._loadDynXML(parentObject.id);
+
+ }
+
+ var Count=parentObject.childsCount;
+ var Nodes=parentObject.childNodes;
+
+
+ if (afterNode){
+ if (afterNode.tr.previousSibling.previousSibling){
+ beforeNode=afterNode.tr.previousSibling.nodem;
+ }
+ else
+ optionStr=optionStr.replace("TOP","")+",TOP";
+ }
+
+ if (beforeNode)
+ {
+ var ik,jk;
+ for (ik=0; ik<Count; ik++)
+ if (Nodes[ik]==beforeNode)
+ {
+ for (jk=Count; jk!=ik; jk--)
+ Nodes[1+jk]=Nodes[jk];
+ break;
+ }
+ ik++;
+ Count=ik;
+ }
+
+
+ if (optionStr) {
+ var tempStr=optionStr.split(",");
+ for (var i=0; i<tempStr.length; i++)
+ {
+ switch(tempStr[i])
+ {
+ case "TOP": if (parentObject.childsCount>0) { beforeNode=new Object; beforeNode.tr=parentObject.childNodes[0].tr.previousSibling; }
+ parentObject._has_top=true;
+ for (ik=Count; ik>0; ik--)
+ Nodes[ik]=Nodes[ik-1];
+ Count=0;
+ break;
+ }
+ };
+ };
+
+ var n;
+ if (!(n=this._idpull[itemId]) || n.span!=-1){
+ n=Nodes[Count]=new dhtmlXTreeItemObject(itemId,itemText,parentObject,this,itemActionHandler,1);
+ itemId = Nodes[Count].id;
+ parentObject.childsCount++;
+ }
+
+ if(!n.htmlNode) {
+ n.label=itemText;
+ n.htmlNode=this._createItem((this.checkBoxOff?1:0),n);
+ n.htmlNode.objBelong=n;
+ }
+
+ if(image1) n.images[0]=image1;
+ if(image2) n.images[1]=image2;
+ if(image3) n.images[2]=image3;
+
+
+ var tr=this._drawNewTr(n.htmlNode);
+ if ((this.XMLloadingWarning)||(this._hAdI))
+ n.htmlNode.parentNode.parentNode.style.display="none";
+
+
+ if ((beforeNode)&&(beforeNode.tr.nextSibling))
+ parentObject.htmlNode.childNodes[0].insertBefore(tr,beforeNode.tr.nextSibling);
+ else
+ if (this.parsingOn==parentObject.id){
+ this.parsedArray[this.parsedArray.length]=tr;
+ }
+ else
+ parentObject.htmlNode.childNodes[0].appendChild(tr);
+
+
+ if ((beforeNode)&&(!beforeNode.span)) beforeNode=null;
+
+ if (this.XMLsource) if ((childs)&&(childs!=0)) n.XMLload=0; else n.XMLload=1;
+ n.tr=tr;
+ tr.nodem=n;
+
+ if (parentObject.itemId==0)
+ tr.childNodes[0].className="hiddenRow";
+
+ if ((parentObject._r_logic)||(this._frbtr))
+ this._setSrc(n.htmlNode.childNodes[0].childNodes[0].childNodes[1].childNodes[0],this.imPath+this.radioArray[0]);
+
+
+ if (optionStr) {
+ var tempStr=optionStr.split(",");
+
+ for (var i=0; i<tempStr.length; i++)
+ {
+ switch(tempStr[i])
+ {
+ case "SELECT": this.selectItem(itemId,false); break;
+ case "CALL": this.selectItem(itemId,true); break;
+ case "CHILD": n.XMLload=0; break;
+ case "CHECKED":
+ if (this.XMLloadingWarning)
+ this.setCheckList+=this.dlmtr+itemId;
+ else
+ this.setCheck(itemId,1);
+ break;
+ case "HCHECKED":
+ this._setCheck(n,"unsure");
+ break;
+ case "OPEN": n.openMe=1; break;
+ }
+ };
+ };
+
+ if (!this.XMLloadingWarning)
+ {
+ if ((this._getOpenState(parentObject)<0)&&(!this._hAdI)) this.openItem(parentObject.id);
+
+ if (beforeNode)
+ {
+ this._correctPlus(beforeNode);
+ this._correctLine(beforeNode);
+ }
+ this._correctPlus(parentObject);
+ this._correctLine(parentObject);
+ this._correctPlus(n);
+ if (parentObject.childsCount>=2)
+ {
+ this._correctPlus(Nodes[parentObject.childsCount-2]);
+ this._correctLine(Nodes[parentObject.childsCount-2]);
+ }
+ if (parentObject.childsCount!=2) this._correctPlus(Nodes[0]);
+
+ if (this.tscheck) this._correctCheckStates(parentObject);
+
+ if (this._onradh) {
+ if (this.xmlstate==1){
+ var old=this.onXLE;
+ this.onXLE=function(id){ this._onradh(itemId); if (old) old(id); }
+ }
+ else
+ this._onradh(itemId);
+ }
+
+ }
+ return n;
+};
+
+
+
+
+/**
+* @desc: create new node as a child to specified with parentId
+* @type: deprecated
+* @param: parentId - parent node id
+* @param: itemId - new node id
+* @param: itemText - new node text
+* @param: itemActionHandler - function fired on node select event (optional)
+* @param: image1 - image for node without children; (optional)
+* @param: image2 - image for closed node; (optional)
+* @param: image3 - image for opened node (optional)
+* @param: optionStr - options string (optional)
+* @param: children - node children flag (for dynamical trees) (optional)
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.insertNewItem=function(parentId,itemId,itemText,itemActionHandler,image1,image2,image3,optionStr,children){
+ var parentObject=this._globalIdStorageFind(parentId);
+ if (!parentObject) return (-1);
+ var nodez=this._attachChildNode(parentObject,itemId,itemText,itemActionHandler,image1,image2,image3,optionStr,children);
+
+ return nodez;
+ };
+/**
+* @desc: create new node as a child to specified with parentId
+* @type: public
+* @param: parentId - parent node id
+* @param: itemId - new node id
+* @param: itemText - new node label
+* @param: itemActionHandler - function fired on node select event (optional)
+* @param: image1 - image for node without children; (optional)
+* @param: image2 - image for closed node; (optional)
+* @param: image3 - image for opened node (optional)
+* @param: optionStr - options string (optional)
+* @param: children - node children flag (for dynamical trees) (optional)
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.insertNewChild=function(parentId,itemId,itemText,itemActionHandler,image1,image2,image3,optionStr,children){
+ return this.insertNewItem(parentId,itemId,itemText,itemActionHandler,image1,image2,image3,optionStr,children);
+ }
+/**
+* @desc: parse xml
+* @type: private
+* @param: dhtmlObject - jsTree object
+* @param: node - top XML node
+* @param: parentId - parent node id
+* @param: level - level of tree
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype._parseXMLTree=function(a,b,c,d,xml){
+ var p=new xmlPointer(xml.getXMLTopNode("tree"));
+ a._parse(p);
+ a._p=p;
+ }
+
+ dhtmlXTreeObject.prototype._parseItem=function(c,temp,preNode,befNode){
+ var id;
+ if (this._srnd && (!this._idpull[id=c.get("id")] || !this._idpull[id].span))
+ {
+ this._addItemSRND(temp.id,id,c);
+ return;
+ }
+
+ var a=c.get_all();
+
+ if ((typeof(this.waitUpdateXML)=="object")&&(!this.waitUpdateXML[a.id])){
+ this._parse(c,a.id,1);
+ return;
+ }
+
+
+
+
+
+
+ var zST=[];
+ if (a.select) zST.push("SELECT");
+ if (a.top) zST.push("TOP");
+ if (a.call) this.nodeAskingCall=a.id;
+ if (a.checked==-1) zST.push("HCHECKED");
+ else if (a.checked) zST.push("CHECKED");
+ if (a.open) zST.push("OPEN");
+
+ if (this.waitUpdateXML){
+ if (this._globalIdStorageFind(a.id))
+ var newNode=this.updateItem(a.id,a.text,a.im0,a.im1,a.im2,a.checked);
+ else{
+ if (this.npl==0) zST.push("TOP");
+ else preNode=temp.childNodes[this.npl];
+
+ var newNode=this._attachChildNode(temp,a.id,a.text,0,a.im0,a.im1,a.im2,zST.join(","),a.child,0,preNode);
+ preNode=null;
+ }
+ }
+ else
+ var newNode=this._attachChildNode(temp,a.id,a.text,0,a.im0,a.im1,a.im2,zST.join(","),a.child,(befNode||0),preNode);
+ if (a.tooltip)
+
+ newNode.span.parentNode.parentNode.title=a.tooltip;
+
+ if (a.style)
+ if (newNode.span.style.cssText)
+ newNode.span.style.cssText+=(";"+a.style);
+ else
+ newNode.span.setAttribute("style",newNode.span.getAttribute("style")+"; "+a.style);
+
+ if (a.radio) newNode._r_logic=true;
+
+ if (a.nocheckbox){
+ newNode.span.parentNode.previousSibling.previousSibling.childNodes[0].style.display='none';
+ newNode.nocheckbox=true;
+ }
+ if (a.disabled){
+ if (a.checked!=null) this._setCheck(newNode,convertStringToBoolean(a.checked));
+ this.disableCheckbox(newNode,1);
+ }
+
+
+ newNode._acc=a.child||0;
+
+ if (this.parserExtension) this.parserExtension._parseExtension.call(this,c,a,(temp?temp.id:0));
+
+ this.setItemColor(newNode,a.aCol,a.sCol);
+ if (a.locked=="1") this.lockItem(newNode.id,true,true);
+
+ if ((a.imwidth)||(a.imheight)) this.setIconSize(a.imwidth,a.imheight,newNode);
+ if ((a.closeable=="0")||(a.closeable=="1")) this.setItemCloseable(newNode,a.closeable);
+ var zcall="";
+ if (a.topoffset) this.setItemTopOffset(newNode,a.topoffset);
+ if ((!this.slowParse)||(typeof(this.waitUpdateXML)=="object")){
+ if (c.sub_exists("item"))
+ zcall=this._parse(c,a.id,1);
+ }
+
+ if (zcall!="") this.nodeAskingCall=zcall;
+
+
+ c.each("userdata",function(u){
+ this.setUserData(c.get("id"),u.get("name"),u.content());
+ },this)
+
+
+ }
+ dhtmlXTreeObject.prototype._parse=function(p,parentId,level,start){
+ if (this._srnd && !this.parentObject.offsetHeight) {
+ var self=this;
+ return window.setTimeout(function(){
+ self._parse(p,parentId,level,start);
+ },100);
+ }
+ if (!p.exists()) return;
+
+ this.skipLock=true; //disable item locking
+ //loading flags
+
+ this.parsCount=this.parsCount?(this.parsCount+1):1;
+ this.XMLloadingWarning=1;
+
+
+ if (!parentId) { //top level
+ parentId=p.get("id");
+ if (p.get("radio"))
+ this.htmlNode._r_logic=true;
+ this.parsingOn=parentId;
+ this.parsedArray=new Array();
+ this.setCheckList="";
+ this.nodeAskingCall="";
+ }
+
+ var temp=this._globalIdStorageFind(parentId);
+ if (!temp) return dhtmlxError.throwError("DataStructure","XML reffers to not existing parent");
+
+ if ((temp.childsCount)&&(!start)&&(!this._edsbps)&&(!temp._has_top))
+ var preNode=temp.childNodes[temp.childsCount-1];
+ else
+ var preNode=0;
+
+ this.npl=0;
+
+ p.each("item",function(c,i){
+
+ temp.XMLload=1;
+ if ((this._epgps)&&(this._epgpsC==this.npl)){
+ this._setNextPageSign(temp,this.npl+1*(start||0),level,node);
+ return -1;
+ }
+
+ this._parseItem(c,temp,preNode);
+
+
+ this.npl++;
+
+
+
+ },this,start);
+
+
+ if (!level) {
+ p.each("userdata",function(u){
+ this.setUserData(p.get("id"),u.get("name"),u.content());
+ },this);
+
+ temp.XMLload=1;
+ if (this.waitUpdateXML){
+ this.waitUpdateXML=false;
+ for (var i=temp.childsCount-1; i>=0; i--)
+ if (temp.childNodes[i]._dmark)
+ this.deleteItem(temp.childNodes[i].id);
+ }
+
+ var parsedNodeTop=this._globalIdStorageFind(this.parsingOn);
+
+ for (var i=0; i<this.parsedArray.length; i++)
+ temp.htmlNode.childNodes[0].appendChild(this.parsedArray[i]);
+
+ this.lastLoadedXMLId=parentId;
+ this.XMLloadingWarning=0;
+
+ var chArr=this.setCheckList.split(this.dlmtr);
+ for (var n=0; n<chArr.length; n++)
+ if (chArr[n]) this.setCheck(chArr[n],1);
+
+ if ((this.XMLsource)&&(this.tscheck)&&(this.smcheck)&&(temp.id!=this.rootId)){
+ if (temp.checkstate===0)
+ this._setSubChecked(0,temp);
+ else if (temp.checkstate===1)
+ this._setSubChecked(1,temp);
+ }
+
+ if (this.onXLE) this.onXLE(this,parentId);
+ this._redrawFrom(this,null,start)
+
+
+ if (p.get("order") && p.get("order")!="none")
+ this._reorderBranch(temp,p.get("order"),true);
+
+ if (this.nodeAskingCall!="") this.selectItem(this.nodeAskingCall,true);
+ if (this._branchUpdate) this._branchUpdateNext(p);
+ }
+
+
+ if (this.parsCount==1) {
+
+
+ this.parsingOn=null;
+ if ((!this._edsbps)||(!this._edsbpsA.length)){
+ var that=this;
+ window.setTimeout( function(){ that.callEvent("onXLE",[that,parentId]); },1);
+ this.xmlstate=0;
+ }
+ this.skipLock=false;
+ }
+ this.parsCount--;
+
+
+
+ if ((this._epgps)&&(start))
+ this._setPrevPageSign(temp,(start||0),level,node);
+
+ return this.nodeAskingCall;
+ };
+
+
+dhtmlXTreeObject.prototype._branchUpdateNext=function(p){
+ p.each("item",function(c){
+ var nid=c.get("id");
+ if (this._idpull[nid] && (!this._idpull[nid].XMLload)) return;
+ this._branchUpdate++;
+ this.smartRefreshItem(c.get("id"),c);
+ },this)
+ this._branchUpdate--;
+}
+
+ dhtmlXTreeObject.prototype.checkUserData=function(node,parentId){
+ if ((node.nodeType==1)&&(node.tagName == "userdata"))
+ {
+ var name=node.getAttribute("name");
+ if ((name)&&(node.childNodes[0]))
+ this.setUserData(parentId,name,node.childNodes[0].data);
+ }
+ }
+
+
+
+
+/**
+* @desc: reset tree images from selected level
+* @type: private
+* @param: dhtmlObject - tree
+* @param: itemObject - current item
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._redrawFrom=function(dhtmlObject,itemObject,start,visMode){
+ if (!itemObject) {
+ var tempx=dhtmlObject._globalIdStorageFind(dhtmlObject.lastLoadedXMLId);
+ dhtmlObject.lastLoadedXMLId=-1;
+ if (!tempx) return 0;
+ }
+ else tempx=itemObject;
+ var acc=0;
+
+ for (var i=(start?start-1:0); i<tempx.childsCount; i++)
+ {
+ if ((!this._branchUpdate)||(this._getOpenState(tempx)==1))
+ if ((!itemObject)||(visMode==1)) tempx.childNodes[i].htmlNode.parentNode.parentNode.style.display="";
+ if (tempx.childNodes[i].openMe==1)
+ {
+ this._openItem(tempx.childNodes[i]);
+ tempx.childNodes[i].openMe=0;
+ }
+
+ dhtmlObject._redrawFrom(dhtmlObject,tempx.childNodes[i]);
+
+
+ };
+
+ if ((!tempx.unParsed)&&((tempx.XMLload)||(!this.XMLsource)))
+ tempx._acc=acc;
+ dhtmlObject._correctLine(tempx);
+ dhtmlObject._correctPlus(tempx);
+
+ };
+
+/**
+* @desc: create and return main html element of tree
+* @type: private
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype._createSelf=function(){
+ var div=document.createElement('div');
+ div.className="containerTableStyle";
+ div.style.width=this.width;
+ div.style.height=this.height;
+ this.parentObject.appendChild(div);
+ return div;
+ };
+
+/**
+* @desc: collapse target node
+* @type: private
+* @param: itemObject - item object
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype._xcloseAll=function(itemObject)
+ {
+ if (itemObject.unParsed) return;
+ if (this.rootId!=itemObject.id) {
+ var Nodes=itemObject.htmlNode.childNodes[0].childNodes;
+ var Count=Nodes.length;
+
+ for (var i=1; i<Count; i++)
+ Nodes[i].style.display="none";
+
+ this._correctPlus(itemObject);
+ }
+
+ for (var i=0; i<itemObject.childsCount; i++)
+ if (itemObject.childNodes[i].childsCount)
+ this._xcloseAll(itemObject.childNodes[i]);
+ };
+/**
+* @desc: expand target node
+* @type: private
+* @param: itemObject - item object
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype._xopenAll=function(itemObject)
+ {
+ this._HideShow(itemObject,2);
+ for (var i=0; i<itemObject.childsCount; i++)
+ this._xopenAll(itemObject.childNodes[i]);
+ };
+/**
+* @desc: set correct tree-line and node images
+* @type: private
+* @param: itemObject - item object
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._correctPlus=function(itemObject){
+ if (!itemObject.htmlNode) return;
+ var imsrc=itemObject.htmlNode.childNodes[0].childNodes[0].childNodes[0].lastChild;
+ var imsrc2=itemObject.htmlNode.childNodes[0].childNodes[0].childNodes[2].childNodes[0];
+
+ var workArray=this.lineArray;
+ if ((this.XMLsource)&&(!itemObject.XMLload))
+ {
+ var workArray=this.plusArray;
+ this._setSrc(imsrc2,this.imPath+itemObject.images[2]);
+ if (this._txtimg) return (imsrc.innerHTML="[+]");
+ }
+ else
+ if ((itemObject.childsCount)||(itemObject.unParsed))
+ {
+ if ((itemObject.htmlNode.childNodes[0].childNodes[1])&&( itemObject.htmlNode.childNodes[0].childNodes[1].style.display!="none" ))
+ {
+ if (!itemObject.wsign) var workArray=this.minusArray;
+ this._setSrc(imsrc2,this.imPath+itemObject.images[1]);
+ if (this._txtimg) return (imsrc.innerHTML="[-]");
+ }
+ else
+ {
+ if (!itemObject.wsign) var workArray=this.plusArray;
+ this._setSrc(imsrc2,this.imPath+itemObject.images[2]);
+ if (this._txtimg) return (imsrc.innerHTML="[+]");
+ }
+ }
+ else
+ {
+ this._setSrc(imsrc2,this.imPath+itemObject.images[0]);
+ }
+
+
+ var tempNum=2;
+ if (!itemObject.treeNod.treeLinesOn) this._setSrc(imsrc,this.imPath+workArray[3]);
+ else {
+ if (itemObject.parentObject) tempNum=this._getCountStatus(itemObject.id,itemObject.parentObject);
+ this._setSrc(imsrc,this.imPath+workArray[tempNum]);
+ }
+ };
+
+/**
+* @desc: set correct tree-line images
+* @type: private
+* @param: itemObject - item object
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._correctLine=function(itemObject){
+ if (!itemObject.htmlNode) return;
+ var sNode=itemObject.parentObject;
+ if (sNode)
+ if ((this._getLineStatus(itemObject.id,sNode)==0)||(!this.treeLinesOn))
+ for(var i=1; i<=itemObject.childsCount; i++){
+ if (!itemObject.htmlNode.childNodes[0].childNodes[i]) break;
+ itemObject.htmlNode.childNodes[0].childNodes[i].childNodes[0].style.backgroundImage="";
+ itemObject.htmlNode.childNodes[0].childNodes[i].childNodes[0].style.backgroundRepeat="";
+ }
+ else
+ for(var i=1; i<=itemObject.childsCount; i++){
+ if (!itemObject.htmlNode.childNodes[0].childNodes[i]) break;
+ itemObject.htmlNode.childNodes[0].childNodes[i].childNodes[0].style.backgroundImage="url("+this.imPath+this.lineArray[5]+")";
+ itemObject.htmlNode.childNodes[0].childNodes[i].childNodes[0].style.backgroundRepeat="repeat-y";
+ }
+ };
+/**
+* @desc: return type of node
+* @type: private
+* @param: itemId - item id
+* @param: itemObject - parent node object
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._getCountStatus=function(itemId,itemObject){
+
+ if (itemObject.childsCount<=1) { if (itemObject.id==this.rootId) return 4; else return 0; }
+
+ if (itemObject.childNodes[0].id==itemId) if (!itemObject.id) return 2; else return 1;
+ if (itemObject.childNodes[itemObject.childsCount-1].id==itemId) return 0;
+
+ return 1;
+ };
+/**
+* @desc: return type of node
+* @type: private
+* @param: itemId - node id
+* @param: itemObject - parent node object
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._getLineStatus =function(itemId,itemObject){
+ if (itemObject.childNodes[itemObject.childsCount-1].id==itemId) return 0;
+ return 1;
+ }
+
+/**
+* @desc: open/close node
+* @type: private
+* @param: itemObject - node object
+* @param: mode - open/close mode [1-close 2-open](optional)
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._HideShow=function(itemObject,mode){
+ if ((this.XMLsource)&&(!itemObject.XMLload)) {
+ if (mode==1) return; //close for not loaded node - ignore it
+ itemObject.XMLload=1;
+ this._loadDynXML(itemObject.id);
+ return; };
+
+ var Nodes=itemObject.htmlNode.childNodes[0].childNodes; var Count=Nodes.length;
+ if (Count>1){
+ if ( ( (Nodes[1].style.display!="none") || (mode==1) ) && (mode!=2) ) {
+//nb:solves standard doctype prb in IE
+ this.allTree.childNodes[0].border = "1";
+ this.allTree.childNodes[0].border = "0";
+ nodestyle="none";
+ }
+ else nodestyle="";
+
+ for (var i=1; i<Count; i++)
+ Nodes[i].style.display=nodestyle;
+ }
+ this._correctPlus(itemObject);
+ }
+
+/**
+* @desc: return node state
+* @type: private
+* @param: itemObject - node object
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._getOpenState=function(itemObject){
+ var z=itemObject.htmlNode.childNodes[0].childNodes;
+ if (z.length<=1) return 0;
+ if (z[1].style.display!="none") return 1;
+ else return -1;
+ }
+
+
+
+/**
+* @desc: ondblclick item event handler
+* @type: private
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.onRowClick2=function(){
+ var that=this.parentObject.treeNod;
+ if (!that.callEvent("onDblClick",[this.parentObject.id,that])) return 0;
+ if ((this.parentObject.closeble)&&(this.parentObject.closeble!="0"))
+ that._HideShow(this.parentObject);
+ else
+ that._HideShow(this.parentObject,2);
+
+ if (that.checkEvent("onOpenEnd"))
+ if (!that.xmlstate)
+ that.callEvent("onOpenEnd",[this.parentObject.id,that._getOpenState(this.parentObject)]);
+ else{
+ that._oie_onXLE.push(that.onXLE);
+ that.onXLE=that._epnFHe;
+ }
+ };
+/**
+* @desc: onclick item event handler
+* @type: private
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.onRowClick=function(){
+ var that=this.parentObject.treeNod;
+ if (!that.callEvent("onOpenStart",[this.parentObject.id,that._getOpenState(this.parentObject)])) return 0;
+ if ((this.parentObject.closeble)&&(this.parentObject.closeble!="0"))
+ that._HideShow(this.parentObject);
+ else
+ that._HideShow(this.parentObject,2);
+//#on_open_end_event:11052006{
+
+ if (that.checkEvent("onOpenEnd"))
+ if (!that.xmlstate)
+ that.callEvent("onOpenEnd",[this.parentObject.id,that._getOpenState(this.parentObject)]);
+ else{
+ that._oie_onXLE.push(that.onXLE);
+ that.onXLE=that._epnFHe;
+ }
+//#}
+ };
+//#on_open_end_event:11052006{
+ dhtmlXTreeObject.prototype._epnFHe=function(that,id,flag){
+ if (id!=this.rootId)
+ this.callEvent("onOpenEnd",[id,that.getOpenState(id)]);
+ that.onXLE=that._oie_onXLE.pop();
+
+ if (!flag && !that._oie_onXLE.length)
+ if (that.onXLE) that.onXLE(that,id);
+ }
+
+//#}
+
+/**
+* @desc: onclick item image event handler
+* @type: private
+* @edition: Professional
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.onRowClickDown=function(e){
+ e=e||window.event;
+ var that=this.parentObject.treeNod;
+ that._selectItem(this.parentObject,e);
+ };
+
+
+/*****
+SELECTION
+*****/
+
+/**
+* @desc: retun selected item id
+* @type: public
+* @return: id of selected item
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype.getSelectedItemId=function()
+ {
+ var str=new Array();
+ for (var i=0; i<this._selected.length; i++) str[i]=this._selected[i].id;
+ return (str.join(this.dlmtr));
+ };
+
+/**
+* @desc: visual select item in tree
+* @type: private
+* @param: node - tree item object
+* @edition: Professional
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype._selectItem=function(node,e){
+ if (this._onSSCF) this._onSSCFold=this.getSelectedItemId();
+
+ this._unselectItems();
+
+ this._markItem(node);
+ if (this._onSSCF) {
+ var z=this.getSelectedItemId();
+ if (z!=this._onSSCFold)
+ this.callEvent("onSelect",[z]);
+ }
+ }
+ dhtmlXTreeObject.prototype._markItem=function(node){
+ if (node.scolor) node.span.style.color=node.scolor;
+ node.span.className="selectedTreeRow";
+ node.i_sel=true;
+ this._selected[this._selected.length]=node;
+ }
+
+/**
+* @desc: retun node index in children collection by Id
+* @type: public
+* @param: itemId - node id
+* @return: node index
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.getIndexById=function(itemId){
+ var z=this._globalIdStorageFind(itemId);
+ if (!z) return null;
+ return this._getIndex(z);
+ };
+ dhtmlXTreeObject.prototype._getIndex=function(w){
+ var z=w.parentObject;
+ for (var i=0; i<z.childsCount; i++)
+ if (z.childNodes[i]==w) return i;
+ };
+
+
+
+
+
+/**
+* @desc: visual unselect item in tree
+* @type: private
+* @param: node - tree item object
+* @edition: Professional
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype._unselectItem=function(node){
+ if ((node)&&(node.i_sel))
+ {
+
+ node.span.className="standartTreeRow";
+ if (node.acolor) node.span.style.color=node.acolor;
+ node.i_sel=false;
+ for (var i=0; i<this._selected.length; i++)
+ if (!this._selected[i].i_sel) {
+ this._selected.splice(i,1);
+ break;
+ }
+
+ }
+ }
+
+/**
+* @desc: visual unselect items in tree
+* @type: private
+* @param: node - tree item object
+* @edition: Professional
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype._unselectItems=function(){
+ for (var i=0; i<this._selected.length; i++){
+ var node=this._selected[i];
+ node.span.className="standartTreeRow";
+ if (node.acolor) node.span.style.color=node.acolor;
+ node.i_sel=false;
+ }
+ this._selected=new Array();
+ }
+
+
+/**
+* @desc: select node text event handler
+* @type: private
+* @param: e - event object
+* @param: htmlObject - node object
+* @param: mode - if false - call onSelect event
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.onRowSelect=function(e,htmlObject,mode){
+ e=e||window.event;
+
+ var obj=this.parentObject;
+ if (htmlObject) obj=htmlObject.parentObject;
+ var that=obj.treeNod;
+
+ var lastId=that.getSelectedItemId();
+ if ((!e)||(!e.skipUnSel))
+ that._selectItem(obj,e);
+
+ if (!mode) {
+ if ((e)&&(e.button==2))
+ that.callEvent("onRightClick",[obj.id,e]);
+
+ if (obj.actionHandler) obj.actionHandler(obj.id,lastId);
+ else that.callEvent("onClick",[obj.id,lastId]);
+ }
+ };
+
+
+
+
+
+/**
+* @desc: fix checkbox state
+* @type: private
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype._correctCheckStates=function(dhtmlObject){
+
+ if (!this.tscheck) return;
+ if (!dhtmlObject) return;
+ if (dhtmlObject.id==this.rootId) return;
+ //calculate state
+ var act=dhtmlObject.childNodes;
+ var flag1=0; var flag2=0;
+ if (dhtmlObject.childsCount==0) return;
+ for (var i=0; i<dhtmlObject.childsCount; i++){
+ if (act[i].dscheck) continue;
+ if (act[i].checkstate==0) flag1=1;
+ else if (act[i].checkstate==1) flag2=1;
+ else { flag1=1; flag2=1; break; }
+ }
+
+ if ((flag1)&&(flag2)) this._setCheck(dhtmlObject,"unsure");
+ else if (flag1) this._setCheck(dhtmlObject,false);
+ else this._setCheck(dhtmlObject,true);
+
+ this._correctCheckStates(dhtmlObject.parentObject);
+}
+
+/**
+* @desc: checbox select action
+* @type: private
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.onCheckBoxClick=function(e){
+ if (!this.treeNod.callEvent("onBeforeCheck",[this.parentObject.id,this.parentObject.checkstate]))
+ return;
+
+ if (this.parentObject.dscheck) return true;
+ if (this.treeNod.tscheck)
+ if (this.parentObject.checkstate==1) this.treeNod._setSubChecked(false,this.parentObject);
+ else this.treeNod._setSubChecked(true,this.parentObject);
+ else
+ if (this.parentObject.checkstate==1) this.treeNod._setCheck(this.parentObject,false);
+ else this.treeNod._setCheck(this.parentObject,true);
+ this.treeNod._correctCheckStates(this.parentObject.parentObject);
+
+ return this.treeNod.callEvent("onCheck",[this.parentObject.id,this.parentObject.checkstate]);
+ };
+/**
+* @desc: create HTML elements for tree node
+* @type: private
+* @param: acheck - enable/disable checkbox
+* @param: itemObject - item object
+* @param: mode - mode
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype._createItem=function(acheck,itemObject,mode){
+
+ var table=document.createElement('table');
+ table.cellSpacing=0;table.cellPadding=0;
+ table.border=0;
+
+ if(this.hfMode)table.style.tableLayout="fixed";
+ table.style.margin=0;table.style.padding=0;
+
+ var tbody=document.createElement('tbody');
+ var tr=document.createElement('tr');
+
+ var td1=document.createElement('td');
+ td1.className="standartTreeImage";
+
+ if(this._txtimg){
+ var img0=document.createElement("div");
+ td1.appendChild(img0);
+ img0.className="dhx_tree_textSign";
+ }
+ else
+ {
+ var img0=this._getImg(itemObject.id);
+ img0.border="0";
+ if (img0.tagName=="IMG") img0.align="absmiddle";
+ td1.appendChild(img0); img0.style.padding=0; img0.style.margin=0;
+ img0.style.width=this.def_line_img_x; img0.style.height=this.def_line_img_y;
+ }
+
+ var td11=document.createElement('td');
+// var inp=document.createElement("input"); inp.type="checkbox"; inp.style.width="12px"; inp.style.height="12px";
+ var inp=this._getImg(this.cBROf?this.rootId:itemObject.id);
+ inp.checked=0; this._setSrc(inp,this.imPath+this.checkArray[0]); inp.style.width="16px"; inp.style.height="16px";
+ //can cause problems with hide/show check
+ if (!acheck) ((!_isIE)?td11:inp).style.display="none";
+
+ // td11.className="standartTreeImage";
+ //if (acheck)
+ td11.appendChild(inp);
+ if ((!this.cBROf)&&(inp.tagName=="IMG")) inp.align="absmiddle";
+ inp.onclick=this.onCheckBoxClick;
+ inp.treeNod=this;
+ inp.parentObject=itemObject;
+ td11.width="20px";
+
+ var td12=document.createElement('td');
+ td12.className="standartTreeImage";
+ var img=this._getImg(this.timgen?itemObject.id:this.rootId);
+ img.onmousedown=this._preventNsDrag; img.ondragstart=this._preventNsDrag;
+ img.border="0";
+ if (this._aimgs){
+ img.parentObject=itemObject;
+ if (img.tagName=="IMG") img.align="absmiddle";
+ img.onclick=this.onRowSelect; }
+ if (!mode) this._setSrc(img,this.imPath+this.imageArray[0]);
+ td12.appendChild(img); img.style.padding=0; img.style.margin=0;
+ if (this.timgen)
+ {
+ td12.style.width=img.style.width=this.def_img_x; img.style.height=this.def_img_y; }
+ else
+ {
+ img.style.width="0px"; img.style.height="0px";
+ if (_isOpera) td12.style.display="none";
+ }
+
+
+ var td2=document.createElement('td');
+ td2.className="standartTreeRow";
+
+ itemObject.span=document.createElement('span');
+ itemObject.span.className="standartTreeRow";
+ if (this.mlitems) {
+ itemObject.span.style.width=this.mlitems;
+ // if (!_isIE)
+ itemObject.span.style.display="block";
+ }
+ else td2.noWrap=true;
+ if (!_isKHTML) td2.style.width="100%";
+
+// itemObject.span.appendChild(document.createTextNode(itemObject.label));
+ itemObject.span.innerHTML=itemObject.label;
+ td2.appendChild(itemObject.span);
+ td2.parentObject=itemObject; td1.parentObject=itemObject;
+ td2.onclick=this.onRowSelect; td1.onclick=this.onRowClick; td2.ondblclick=this.onRowClick2;
+ if (this.ettip)
+
+ tr.title=itemObject.label;
+
+ if (this.dragAndDropOff) {
+ if (this._aimgs) { this.dragger.addDraggableItem(td12,this); td12.parentObject=itemObject; }
+ this.dragger.addDraggableItem(td2,this);
+ }
+
+ itemObject.span.style.paddingLeft="5px"; itemObject.span.style.paddingRight="5px"; td2.style.verticalAlign="";
+ td2.style.fontSize="10pt"; td2.style.cursor=this.style_pointer;
+ tr.appendChild(td1); tr.appendChild(td11); tr.appendChild(td12);
+ tr.appendChild(td2);
+ tbody.appendChild(tr);
+ table.appendChild(tbody);
+
+ if (this.ehlt){//highlighting
+ tr.onmousemove=this._itemMouseIn;
+ tr[(_isIE)?"onmouseleave":"onmouseout"]=this._itemMouseOut;
+ }
+ if(this.checkEvent && this.checkEvent("onRightClick"))
+ tr.oncontextmenu=Function("e","this.childNodes[0].parentObject.treeNod.callEvent('onRightClick',[this.childNodes[0].parentObject.id,(e||window.event)]); return false;");
+
+
+ return table;
+ };
+
+
+/**
+* @desc: set path to images directory
+* @param: newPath - path to images directory (related to the page with tree or absolute http url)
+* @type: public
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.setImagePath=function( newPath ){ this.imPath=newPath; };
+
+
+
+/**
+* @desc: set function called when tree node selected
+* @param: (function) func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onRightClick
+* @depricated: use grid.attachEvent("onRightClick",func); instead
+* @eventdesc: Event occurs after right mouse button was clicked.
+ Assigning this handler can disable default context menu, and incompattible with dhtmlXMenu integration.
+* @eventparam: (string) ID of clicked item
+* @eventparam: (object) event object
+*/
+ dhtmlXTreeObject.prototype.setOnRightClickHandler=function(func){ this.attachEvent("onRightClick",func); };
+
+/**
+* @desc: set function called when tree node clicked, also can be forced to call from API
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onClick
+* @depricated: use grid.attachEvent("onClick",func); instead
+* @eventdesc: Event raises immideatly after text part of item in tree was clicked, but after default onClick functionality was processed.
+ Richt mouse button click can be catched by onRightClick event handler.
+* @eventparam: ID of clicked item
+* @eventparam: ID of previously selected item
+*/
+ dhtmlXTreeObject.prototype.setOnClickHandler=function(func){ this.attachEvent("onClick",func); };
+
+/**
+* @desc: set function called when tree node selected or unselected, include any select change caused by any functionality
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onSelect
+* @depricated: use grid.attachEvent("onSelect",func); instead
+* @eventdesc: Event raises immideatly after selection in tree was changed
+* @eventparam: selected item ID ( list of IDs in case of multiselection)
+*/
+ dhtmlXTreeObject.prototype.setOnSelectStateChange=function(func){ this.attachEvent("onSelect",func); this._onSSCF=true; };
+
+
+/**
+* @desc: enables dynamic loading from XML
+* @type: public
+* @param: filePath - name of script returning XML; in case of virtual loading - user defined function
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.setXMLAutoLoading=function(filePath){ this.XMLsource=filePath; };
+
+ /**
+* @desc: set function called before checkbox checked/unchecked
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onCheck
+* @depricated: use tree.attachEvent("onCheck",func); instead
+* @eventdesc: Event raises right before item in tree was checked/unchecked. can be canceled (return false from event handler)
+* @eventparam: ID of item which will be checked/unchecked
+* @eventparam: Current checkbox state. 1 - item checked, 0 - item unchecked.
+* @eventreturn: true - confirm changing checked state; false - deny chaning checked state;
+*/
+ dhtmlXTreeObject.prototype.setOnCheckHandler=function(func){ this.attachEvent("onCheck",func); };
+
+
+/**
+* @desc: set function called before tree node opened/closed
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onOpen
+* @depricated: use grid.attachEvent("onOpenStart",func); instead
+* @eventdesc: Event raises immideatly after item in tree got command to open/close , and before item was opened//closed. Event also raised for unclosable nodes and nodes without open/close functionality - in that case result of function will be ignored.
+ Event does not occur if node was opened by dhtmlXtree API.
+* @eventparam: ID of node which will be opened/closed
+* @eventparam: Current open state of tree item. 0 - item has not children, -1 - item closed, 1 - item opened.
+* @eventreturn: true - confirm opening/closing; false - deny opening/closing;
+*/
+ dhtmlXTreeObject.prototype.setOnOpenHandler=function(func){ this.attachEvent("onOpenStart",func); };
+/**
+* @desc: set function called before tree node opened/closed
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onOpenStart
+* @depricated: use grid.attachEvent("onOpenStart",func); instead
+* @eventdesc: Event raises immideatly after item in tree got command to open/close , and before item was opened//closed. Event also raised for unclosable nodes and nodes without open/close functionality - in that case result of function will be ignored.
+ Event not raised if node opened by dhtmlXtree API.
+* @eventparam: ID of node which will be opened/closed
+* @eventparam: Current open state of tree item. 0 - item has not children, -1 - item closed, 1 - item opened.
+* @eventreturn: true - confirm opening/closing; false - deny opening/closing;
+*/
+ dhtmlXTreeObject.prototype.setOnOpenStartHandler=function(func){ this.attachEvent("onOpenStart",func); };
+
+/**
+* @desc: set function called after tree node opened/closed
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onOpenEnd
+* @depricated: use grid.attachEvent("onOpenEnd",func); instead
+* @eventdesc: Event raises immideatly after item in tree was opened//closed. Event also raised for unclosable nodes and nodes without open/close functionality - in that case result of function will be ignored.
+ Event not raised if node opened by dhtmlXtree API.
+* @eventparam: ID of node which will be opened/closed
+* @eventparam: Current open state of tree item. 0 - item has not children, -1 - item closed, 1 - item opened.
+*/
+ dhtmlXTreeObject.prototype.setOnOpenEndHandler=function(func){ this.attachEvent("onOpenEnd",func); };
+
+ /**
+* @desc: set function called when tree node double clicked
+* @param: func - event handling function
+* @type: public
+* @topic: 0,7
+* @event: onDblClick
+* @depricated: use grid.attachEvent("onDblClick",func); instead
+* @eventdesc: Event raised immideatly after item in tree was doubleclicked, before default onDblClick functionality was processed.
+ Beware using both onClick and onDblClick events, because component can generate onClick event before onDblClick event while doubleclicking item in tree.
+ ( that behavior depend on used browser )
+* @eventparam: ID of item which was doubleclicked
+* @eventreturn: true - confirm opening/closing; false - deny opening/closing;
+*/
+ dhtmlXTreeObject.prototype.setOnDblClickHandler=function(func){ this.attachEvent("onDblClick",func); };
+
+
+
+
+
+
+
+
+
+ /**
+* @desc: expand target node and all sub nodes
+* @type: public
+* @param: itemId - node id
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.openAllItems=function(itemId)
+ {
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ this._xopenAll(temp);
+ };
+
+/**
+* @desc: return open/close state
+* @type: public
+* @param: itemId - node id
+* @return: -1 - close, 1 - opened, 0 - node doesn't have children
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.getOpenState=function(itemId){
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return "";
+ return this._getOpenState(temp);
+ };
+
+/**
+* @desc: collapse target node and all sub nodes
+* @type: public
+* @param: itemId - node id
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.closeAllItems=function(itemId)
+ {
+ if (itemId===window.undefined) itemId=this.rootId;
+
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ this._xcloseAll(temp);
+
+//nb:solves standard doctype prb in IE
+ this.allTree.childNodes[0].border = "1";
+ this.allTree.childNodes[0].border = "0";
+
+ };
+
+
+/**
+* @desc: set user data for target node
+* @type: public
+* @param: itemId - target node id
+* @param: name - key for user data
+* @param: value - user data value
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.setUserData=function(itemId,name,value){
+ var sNode=this._globalIdStorageFind(itemId,0,true);
+ if (!sNode) return;
+ if(name=="hint")
+
+ sNode.htmlNode.childNodes[0].childNodes[0].title=value;
+ if (typeof(sNode.userData["t_"+name])=="undefined"){
+ if (!sNode._userdatalist) sNode._userdatalist=name;
+ else sNode._userdatalist+=","+name;
+ }
+ sNode.userData["t_"+name]=value;
+ };
+
+/**
+* @desc: get user data from target node
+* @type: public
+* @param: itemId - target node id
+* @param: name - key for user data
+* @return: value of user data
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.getUserData=function(itemId,name){
+ var sNode=this._globalIdStorageFind(itemId,0,true);
+ if (!sNode) return;
+ return sNode.userData["t_"+name];
+ };
+
+
+
+
+/**
+* @desc: get node color (text color)
+* @param: itemId - id of node
+* @type: public
+* @return: color of node (empty string for default color);
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.getItemColor=function(itemId)
+ {
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+
+ var res= new Object();
+ if (temp.acolor) res.acolor=temp.acolor;
+ if (temp.acolor) res.scolor=temp.scolor;
+ return res;
+ };
+/**
+* @desc: set node text color
+* @param: itemId - id of node
+* @param: defaultColor - node color
+* @param: selectedColor - selected node color
+* @type: public
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.setItemColor=function(itemId,defaultColor,selectedColor)
+ {
+ if ((itemId)&&(itemId.span))
+ var temp=itemId;
+ else
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ else {
+ if (temp.i_sel)
+ { if (selectedColor) temp.span.style.color=selectedColor; }
+ else
+ { if (defaultColor) temp.span.style.color=defaultColor; }
+
+ if (selectedColor) temp.scolor=selectedColor;
+ if (defaultColor) temp.acolor=defaultColor;
+ }
+ };
+
+/**
+* @desc: return node text
+* @param: itemId - id of node
+* @type: public
+* @return: text of item (with HTML formatting, if any)
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.getItemText=function(itemId)
+ {
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ return(temp.htmlNode.childNodes[0].childNodes[0].childNodes[3].childNodes[0].innerHTML);
+ };
+/**
+* @desc: return parent item id
+* @param: itemId - id of node
+* @type: public
+* @return: id of parent item
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.getParentId=function(itemId)
+ {
+ var temp=this._globalIdStorageFind(itemId);
+ if ((!temp)||(!temp.parentObject)) return "";
+ return temp.parentObject.id;
+ };
+
+
+
+/**
+* @desc: change item id
+* @type: public
+* @param: itemId - old node id
+* @param: newItemId - new node id
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.changeItemId=function(itemId,newItemId)
+ {
+ if (itemId==newItemId) return;
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ temp.id=newItemId;
+ temp.span.contextMenuId=newItemId;
+ this._idpull[newItemId]=this._idpull[itemId];
+ delete this._idpull[itemId];
+ };
+
+
+/**
+* @desc: mark selected item as cut
+* @type: public
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.doCut=function(){
+ if (this.nodeCut) this.clearCut();
+ this.nodeCut=(new Array()).concat(this._selected);
+ for (var i=0; i<this.nodeCut.length; i++){
+ var tempa=this.nodeCut[i];
+ tempa._cimgs=new Array();
+ tempa._cimgs[0]=tempa.images[0];
+ tempa._cimgs[1]=tempa.images[1];
+ tempa._cimgs[2]=tempa.images[2];
+ tempa.images[0]=tempa.images[1]=tempa.images[2]=this.cutImage;
+ this._correctPlus(tempa);
+ }
+ };
+
+/**
+* @desc: insert previously cut branch
+* @param: itemId - id of new parent node
+* @type: public
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.doPaste=function(itemId){
+ var tobj=this._globalIdStorageFind(itemId);
+ if (!tobj) return 0;
+ for (var i=0; i<this.nodeCut.length; i++){
+ if (this._checkPNodes(tobj,this.nodeCut[i])) continue;
+ this._moveNode(this.nodeCut[i],tobj);
+ }
+ this.clearCut();
+ };
+
+/**
+* @desc: clear cut
+* @type: public
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.clearCut=function(){
+ for (var i=0; i<this.nodeCut.length; i++)
+ {
+ var tempa=this.nodeCut[i];
+ tempa.images[0]=tempa._cimgs[0];
+ tempa.images[1]=tempa._cimgs[1];
+ tempa.images[2]=tempa._cimgs[2];
+ this._correctPlus(tempa);
+ }
+ this.nodeCut=new Array();
+ };
+
+
+
+ /**
+* @desc: move node with subnodes
+* @type: private
+* @param: itemObject - moved node object
+* @param: targetObject - new parent node
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype._moveNode=function(itemObject,targetObject){
+
+ return this._moveNodeTo(itemObject,targetObject);
+
+ }
+
+ /**
+* @desc: fix order of nodes in collection
+* @type: private
+* @param: target - parent item node
+* @param: zParent - before node
+* @edition: Professional
+* @topic: 2
+*/
+
+dhtmlXTreeObject.prototype._fixNodesCollection=function(target,zParent){
+ var flag=0; var icount=0;
+ var Nodes=target.childNodes;
+ var Count=target.childsCount-1;
+
+ if (zParent==Nodes[Count]) return;
+ for (var i=0; i<Count; i++)
+ if (Nodes[i]==Nodes[Count]) { Nodes[i]=Nodes[i+1]; Nodes[i+1]=Nodes[Count]; }
+
+// Count=target.childsCount;
+ for (var i=0; i<Count+1; i++)
+ {
+ if (flag) {
+ var temp=Nodes[i];
+ Nodes[i]=flag;
+ flag=temp;
+ }
+ else
+ if (Nodes[i]==zParent) { flag=Nodes[i]; Nodes[i]=Nodes[Count]; }
+ }
+ };
+
+/**
+* @desc: recreate branch
+* @type: private
+* @param: itemObject - moved node object
+* @param: targetObject - new parent node
+* @param: level - top level flag
+* @param: beforeNode - node for sibling mode
+* @mode: mode - DragAndDrop mode (0 - as child, 1 as sibling)
+* @edition: Professional
+* @topic: 2
+*/
+dhtmlXTreeObject.prototype._recreateBranch=function(itemObject,targetObject,beforeNode,level){
+ var i; var st="";
+ if (beforeNode){
+ for (i=0; i<targetObject.childsCount; i++)
+ if (targetObject.childNodes[i]==beforeNode) break;
+
+ if (i!=0)
+ beforeNode=targetObject.childNodes[i-1];
+ else{
+ st="TOP";
+ beforeNode="";
+ }
+ }
+
+ var t2=this._onradh; this._onradh=null;
+ var newNode=this._attachChildNode(targetObject,itemObject.id,itemObject.label,0,itemObject.images[0],itemObject.images[1],itemObject.images[2],st,0,beforeNode);
+
+ //copy user data
+ newNode._userdatalist=itemObject._userdatalist;
+ newNode.userData=itemObject.userData.clone();
+ newNode.XMLload=itemObject.XMLload;
+ if (t2){
+ this._onradh=t2; this._onradh(newNode.id); }
+
+
+ for (var i=0; i<itemObject.childsCount; i++)
+ this._recreateBranch(itemObject.childNodes[i],newNode,0,1);
+
+
+ return newNode;
+}
+
+/**
+* @desc: move single node
+* @type: private
+* @param: itemObject - moved node object
+* @param: targetObject - new parent node
+* @mode: mode - DragAndDrop mode (0 - as child, 1 as sibling)
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype._moveNodeTo=function(itemObject,targetObject,beforeNode){
+ //return;
+ if (itemObject.treeNod._nonTrivialNode)
+ return itemObject.treeNod._nonTrivialNode(this,targetObject,beforeNode,itemObject);
+
+ if (targetObject.mytype)
+ var framesMove=(itemObject.treeNod.lWin!=targetObject.lWin);
+ else
+ var framesMove=(itemObject.treeNod.lWin!=targetObject.treeNod.lWin);
+
+ if (!this.callEvent("onDrag",[itemObject.id,targetObject.id,(beforeNode?beforeNode.id:null),itemObject.treeNod,targetObject.treeNod])) return false;
+ if ((targetObject.XMLload==0)&&(this.XMLsource))
+ {
+ targetObject.XMLload=1;
+ this._loadDynXML(targetObject.id);
+ }
+ this.openItem(targetObject.id);
+
+ var oldTree=itemObject.treeNod;
+ var c=itemObject.parentObject.childsCount;
+ var z=itemObject.parentObject;
+
+
+ if ((framesMove)||(oldTree.dpcpy)) {//interframe drag flag
+ var _otiid=itemObject.id;
+ itemObject=this._recreateBranch(itemObject,targetObject,beforeNode);
+ if (!oldTree.dpcpy) oldTree.deleteItem(_otiid);
+ }
+ else
+ {
+
+ var Count=targetObject.childsCount; var Nodes=targetObject.childNodes;
+ if (Count==0) targetObject._open=true;
+ oldTree._unselectItem(itemObject);
+ Nodes[Count]=itemObject;
+ itemObject.treeNod=targetObject.treeNod;
+ targetObject.childsCount++;
+
+ var tr=this._drawNewTr(Nodes[Count].htmlNode);
+
+ if (!beforeNode)
+ {
+ targetObject.htmlNode.childNodes[0].appendChild(tr);
+ if (this.dadmode==1) this._fixNodesCollection(targetObject,beforeNode);
+ }
+ else
+ {
+ targetObject.htmlNode.childNodes[0].insertBefore(tr,beforeNode.tr);
+ this._fixNodesCollection(targetObject,beforeNode);
+ Nodes=targetObject.childNodes;
+ }
+
+
+ }
+
+ if ((!oldTree.dpcpy)&&(!framesMove)) {
+ var zir=itemObject.tr;
+
+ if ((document.all)&&(navigator.appVersion.search(/MSIE\ 5\.0/gi)!=-1))
+ {
+ window.setTimeout(function() { zir.parentNode.removeChild(zir); } , 250 );
+ }
+ else //if (zir.parentNode) zir.parentNode.removeChild(zir,true);
+
+ itemObject.parentObject.htmlNode.childNodes[0].removeChild(itemObject.tr);
+
+ //itemObject.tr.removeNode(true);
+ if ((!beforeNode)||(targetObject!=itemObject.parentObject)){
+ for (var i=0; i<z.childsCount; i++){
+ if (z.childNodes[i].id==itemObject.id) {
+ z.childNodes[i]=0;
+ break; }}}
+ else z.childNodes[z.childsCount-1]=0;
+
+ oldTree._compressChildList(z.childsCount,z.childNodes);
+ z.childsCount--;
+ }
+
+
+ if ((!framesMove)&&(!oldTree.dpcpy)) {
+ itemObject.tr=tr;
+ tr.nodem=itemObject;
+ itemObject.parentObject=targetObject;
+
+ if (oldTree!=targetObject.treeNod) { if(itemObject.treeNod._registerBranch(itemObject,oldTree)) return; this._clearStyles(itemObject); this._redrawFrom(this,itemObject.parentObject); };
+
+ this._correctPlus(targetObject);
+ this._correctLine(targetObject);
+
+ this._correctLine(itemObject);
+ this._correctPlus(itemObject);
+
+ //fix target siblings
+ if (beforeNode)
+ {
+
+ this._correctPlus(beforeNode);
+ //this._correctLine(beforeNode);
+ }
+ else
+ if (targetObject.childsCount>=2)
+ {
+
+ this._correctPlus(Nodes[targetObject.childsCount-2]);
+ this._correctLine(Nodes[targetObject.childsCount-2]);
+ }
+
+ this._correctPlus(Nodes[targetObject.childsCount-1]);
+ //this._correctLine(Nodes[targetObject.childsCount-1]);
+
+
+ if (this.tscheck) this._correctCheckStates(targetObject);
+ if (oldTree.tscheck) oldTree._correctCheckStates(z);
+
+ }
+
+ //fix source parent
+
+ if (c>1) { oldTree._correctPlus(z.childNodes[c-2]);
+ oldTree._correctLine(z.childNodes[c-2]);
+ }
+
+
+// if (z.childsCount==0)
+ oldTree._correctPlus(z);
+ oldTree._correctLine(z);
+
+
+ this.callEvent("onDrop",[itemObject.id,targetObject.id,(beforeNode?beforeNode.id:null),oldTree,targetObject.treeNod]);
+ return itemObject.id;
+ };
+
+
+
+/**
+* @desc: recursive set default styles for node
+* @type: private
+* @param: itemObject - target node object
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._clearStyles=function(itemObject){
+ if (!itemObject.htmlNode) return; //some weird case in SRND mode
+ var td1=itemObject.htmlNode.childNodes[0].childNodes[0].childNodes[1];
+ var td3=td1.nextSibling.nextSibling;
+
+ itemObject.span.innerHTML=itemObject.label;
+ itemObject.i_sel=false;
+
+ if (itemObject._aimgs)
+ this.dragger.removeDraggableItem(td1.nextSibling);
+
+ if (this.checkBoxOff) {
+ td1.childNodes[0].style.display="";
+ td1.childNodes[0].onclick=this.onCheckBoxClick;
+ this._setSrc(td1.childNodes[0],this.imPath+this.checkArray[itemObject.checkstate]);
+ }
+ else td1.childNodes[0].style.display="none";
+ td1.childNodes[0].treeNod=this;
+
+ this.dragger.removeDraggableItem(td3);
+ if (this.dragAndDropOff) this.dragger.addDraggableItem(td3,this);
+ if (this._aimgs) this.dragger.addDraggableItem(td1.nextSibling,this);
+
+ td3.childNodes[0].className="standartTreeRow";
+ td3.onclick=this.onRowSelect; td3.ondblclick=this.onRowClick2;
+ td1.previousSibling.onclick=this.onRowClick;
+
+ this._correctLine(itemObject);
+ this._correctPlus(itemObject);
+ for (var i=0; i<itemObject.childsCount; i++) this._clearStyles(itemObject.childNodes[i]);
+
+ };
+/**
+* @desc: register node and all children nodes
+* @type: private
+* @param: itemObject - node object
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype._registerBranch=function(itemObject,oldTree){
+ if (oldTree) oldTree._globalIdStorageSub(itemObject.id);
+ itemObject.id=this._globalIdStorageAdd(itemObject.id,itemObject);
+ itemObject.treeNod=this;
+ for (var i=0; i<itemObject.childsCount; i++)
+ this._registerBranch(itemObject.childNodes[i],oldTree);
+ return 0;
+ };
+
+
+/**
+* @desc: enable three state checkboxes
+* @beforeInit: 1
+* @param: mode - 1 - on, 0 - off;
+* @type: public
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableThreeStateCheckboxes=function(mode) { this.tscheck=convertStringToBoolean(mode); };
+
+
+/**
+* @desc: set function called when mouse is over tree node
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onMouseIn
+* @depricated: use grid.attachEvent("onMouseIn",func); instead
+* @eventdesc: Event raised immideatly after mouse started moving over item
+* @eventparam: ID of item
+*/
+ dhtmlXTreeObject.prototype.setOnMouseInHandler=function(func){
+ this.ehlt=true;
+ this.attachEvent("onMouseIn",func);
+ };
+
+/**
+* @desc: set function called when mouse is out of tree node
+* @param: func - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onMouseOut
+* @depricated: use grid.attachEvent("onMouseOut",func); instead
+* @eventdesc: Event raised immideatly after mouse moved out of item
+* @eventparam: ID of clicked item
+*/
+ dhtmlXTreeObject.prototype.setOnMouseOutHandler=function(func){
+ this.ehlt=true;
+ this.attachEvent("onMouseOut",func);
+ };
+
+
+
+
+
+
+
+
+
+/**
+* @desc: enable tree images
+* @beforeInit: 1
+* @param: mode - 1 - on, 0 - off;
+* @type: public
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableTreeImages=function(mode) { this.timgen=convertStringToBoolean(mode); };
+
+
+
+/**
+* @desc: enable mode with fixed tables (looks better, but has no horisontal scrollbar)
+* @beforeInit: 1
+* @param: mode - 1 - on, 0 - off;
+* @type: private
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableFixedMode=function(mode) { this.hfMode=convertStringToBoolean(mode); };
+
+/**
+* @desc: show/hide checkboxes (all checkboxes in tree)
+* @type: public
+* @param: mode - true/false
+* @param: hidden - if set to true, checkboxes not rendered but can be shown by showItemCheckbox
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableCheckBoxes=function(mode, hidden){ this.checkBoxOff=convertStringToBoolean(mode); this.cBROf=(!(this.checkBoxOff||convertStringToBoolean(hidden)));
+ };
+/**
+* @desc: set default images for nodes (must be called before XML loading)
+* @type: public
+* @param: a0 - image for node without children;
+* @param: a1 - image for closed node;
+* @param: a2 - image for opened node
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.setStdImages=function(image1,image2,image3){
+ this.imageArray[0]=image1; this.imageArray[1]=image2; this.imageArray[2]=image3;};
+
+/**
+* @desc: enable/disable tree lines (parent-child threads)
+* @type: public
+* @param: mode - enable/disable tree lines
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.enableTreeLines=function(mode){
+ this.treeLinesOn=convertStringToBoolean(mode);
+ }
+
+/**
+* @desc: set images used for parent-child threads drawing (lines, plus, minus)
+* @type: public
+* @param: arrayName - name of array: plus, minus
+* @param: image1 - line crossed image
+* @param: image2 - image with top line
+* @param: image3 - image with bottom line
+* @param: image4 - image without line
+* @param: image5 - single root image
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.setImageArrays=function(arrayName,image1,image2,image3,image4,image5){
+ switch(arrayName){
+ case "plus": this.plusArray[0]=image1; this.plusArray[1]=image2; this.plusArray[2]=image3; this.plusArray[3]=image4; this.plusArray[4]=image5; break;
+ case "minus": this.minusArray[0]=image1; this.minusArray[1]=image2; this.minusArray[2]=image3; this.minusArray[3]=image4; this.minusArray[4]=image5; break;
+ }
+ };
+
+/**
+* @desc: expand node
+* @param: itemId - id of node
+* @type: public
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.openItem=function(itemId){
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ else return this._openItem(temp);
+ };
+
+/**
+* @desc: expand node
+* @param: item - tree node object
+* @type: private
+* @editing: pro
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype._openItem=function(item){
+ var state=this._getOpenState(item);
+ if ((state<0)||(((this.XMLsource)&&(!item.XMLload)))){
+ if (!this.callEvent("onOpenStart",[item.id,state])) return 0;
+ this._HideShow(item,2);
+ //#on_open_end_event:11052006{
+ if (this.checkEvent("onOpenEnd")){
+ if (this.onXLE==this._epnFHe) this._epnFHe(this,item.id,true);
+ if (!this.xmlstate || !this.XMLsource)
+ this.callEvent("onOpenEnd",[item.id,this._getOpenState(item)]);
+ else{
+ this._oie_onXLE.push(this.onXLE);
+ this.onXLE=this._epnFHe;
+ }
+ }
+ //#}
+ } else if (this._srnd) this._HideShow(item,2);
+ if (item.parentObject) this._openItem(item.parentObject);
+ };
+
+/**
+* @desc: collapse node
+* @param: itemId - id of node
+* @type: public
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.closeItem=function(itemId){
+ if (this.rootId==itemId) return 0;
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ if (temp.closeble)
+ this._HideShow(temp,1);
+ };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+* @desc: get node level (position in hierarchy)
+* @param: itemId - id of node
+* @type: public
+* @return: node level (0 if no such item in hierarchy - probably super root)
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.getLevel=function(itemId){
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ return this._getNodeLevel(temp,0);
+ };
+
+
+
+/**
+* @desc: prevent node from closing
+* @param: itemId - id of node
+* @param: flag - if 0 - node can't be closed, else node can be closed
+* @type: public
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.setItemCloseable=function(itemId,flag)
+ {
+ flag=convertStringToBoolean(flag);
+ if ((itemId)&&(itemId.span))
+ var temp=itemId;
+ else
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ temp.closeble=flag;
+ };
+
+ /**
+* @desc: recursive function used for node level calculation
+* @param: itemObject - pointer to node object
+* @param: count - counter of levels
+* @type: private
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype._getNodeLevel=function(itemObject,count){
+ if (itemObject.parentObject) return this._getNodeLevel(itemObject.parentObject,count+1);
+ return(count);
+ };
+
+ /**
+* @desc: return number of children
+* @param: itemId - id of node
+* @type: public
+* @return: number of child items for loaded branches; true - for not loaded branches
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype.hasChildren=function(itemId){
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ else
+ {
+ if ( (this.XMLsource)&&(!temp.XMLload) ) return true;
+ else
+ return temp.childsCount;
+ };
+ };
+
+
+ /**
+* @desc: get number of leafs (nodes without children)
+* @param: itemNode - node object
+* @type: private
+* @edition: Professional
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype._getLeafCount=function(itemNode){
+ var a=0;
+ for (var b=0; b<itemNode.childsCount; b++)
+ if (itemNode.childNodes[b].childsCount==0) a++;
+ return a;
+ }
+
+
+/**
+* @desc: set new node text (HTML allowed)
+* @param: itemId - id of node
+* @param: newLabel - node text
+* @param: newTooltip - (optional)tooltip for the node
+* @type: public
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.setItemText=function(itemId,newLabel,newTooltip)
+ {
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ temp.label=newLabel;
+ temp.span.innerHTML=newLabel;
+
+ temp.span.parentNode.parentNode.title=newTooltip||"";
+ };
+
+/**
+* @desc: get item's tooltip
+* @param: itemId - id of node
+* @type: public
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.getItemTooltip=function(itemId){
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return "";
+ return (temp.span.parentNode.parentNode._dhx_title||temp.span.parentNode.parentNode.title||"");
+ };
+
+/**
+* @desc: refresh tree branch from xml (XML with child nodes rerequested from server)
+* @param: itemId - id of node, if not defined tree super root used.
+* @type: public
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.refreshItem=function(itemId){
+ if (!itemId) itemId=this.rootId;
+ var temp=this._globalIdStorageFind(itemId);
+ this.deleteChildItems(itemId);
+ this._loadDynXML(itemId);
+ };
+
+ /**
+* @desc: set item images
+* @param: itemId - id of node
+* @param: image1 - node without children icon
+* @param: image2 - closed node icon
+* @param: image3 - open node icon
+* @type: public
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.setItemImage2=function(itemId, image1,image2,image3){
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ temp.images[1]=image2;
+ temp.images[2]=image3;
+ temp.images[0]=image1;
+ this._correctPlus(temp);
+ };
+/**
+* @desc: set item icons (mostly usefull for childless nodes)
+* @param: itemId - id of node
+* @param: image1 - node without children icon or closed node icon (if image2 specified)
+* @param: image2 - open node icon (optional)
+* @type: public
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.setItemImage=function(itemId,image1,image2)
+ {
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ if (image2)
+ {
+ temp.images[1]=image1;
+ temp.images[2]=image2;
+ }
+ else temp.images[0]=image1;
+ this._correctPlus(temp);
+ };
+
+
+/**
+* @desc: Returns the list of all subitems Ids from the next level of tree, separated by commas.
+* @param: itemId - id of node
+* @type: public
+* @return: list of all subitems from the next level of tree, separated by commas.
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.getSubItems =function(itemId)
+ {
+ var temp=this._globalIdStorageFind(itemId,0,1);
+ if (!temp) return 0;
+
+ var z="";
+ for (i=0; i<temp.childsCount; i++){
+ if (!z) z=temp.childNodes[i].id;
+ else z+=this.dlmtr+temp.childNodes[i].id;
+
+ }
+
+ return z;
+ };
+
+
+
+
+/**
+* @desc: Returns the list of all sub items from all next levels of tree, separated by commas.
+* @param: itemId - id of node
+* @edition: Professional
+* @type: private
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._getAllScraggyItems =function(node)
+ {
+ var z="";
+ for (var i=0; i<node.childsCount; i++)
+ {
+ if ((node.childNodes[i].unParsed)||(node.childNodes[i].childsCount>0))
+ {
+ if (node.childNodes[i].unParsed)
+ var zb=this._getAllScraggyItemsXML(node.childNodes[i].unParsed,1);
+ else
+ var zb=this._getAllScraggyItems(node.childNodes[i])
+
+ if (zb)
+ if (z) z+=this.dlmtr+zb;
+ else z=zb;
+ }
+ else
+ if (!z) z=node.childNodes[i].id;
+ else z+=this.dlmtr+node.childNodes[i].id;
+ }
+ return z;
+ };
+
+
+
+
+
+/**
+* @desc: Returns the list of all children items from all next levels of tree, separated by commas.
+* @param: itemId - id of node
+* @type: private
+* @edition: Professional
+* @topic: 6
+*/
+
+ dhtmlXTreeObject.prototype._getAllFatItems =function(node)
+ {
+ var z="";
+ for (var i=0; i<node.childsCount; i++)
+ {
+ if ((node.childNodes[i].unParsed)||(node.childNodes[i].childsCount>0))
+ {
+ if (!z) z=node.childNodes[i].id;
+ else z+=this.dlmtr+node.childNodes[i].id;
+
+ if (node.childNodes[i].unParsed)
+ var zb=this._getAllFatItemsXML(node.childNodes[i].unParsed,1);
+ else
+ var zb=this._getAllFatItems(node.childNodes[i])
+
+ if (zb) z+=this.dlmtr+zb;
+ }
+ }
+ return z;
+ };
+
+
+/**
+* @desc: Returns the list of all children items from all next levels of tree, separated by commas.
+* @param: itemId - id of node
+* @type: private
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._getAllSubItems =function(itemId,z,node)
+ {
+ if (node) temp=node;
+ else {
+ var temp=this._globalIdStorageFind(itemId);
+ };
+ if (!temp) return 0;
+
+ z="";
+ for (var i=0; i<temp.childsCount; i++)
+ {
+ if (!z) z=temp.childNodes[i].id;
+ else z+=this.dlmtr+temp.childNodes[i].id;
+ var zb=this._getAllSubItems(0,z,temp.childNodes[i])
+
+ if (zb) z+=this.dlmtr+zb;
+ }
+
+
+ return z;
+ };
+
+
+
+
+
+/**
+* @desc: select node ( and optionaly fire onselect event)
+* @type: public
+* @param: itemId - node id
+* @param: mode - If true, script function for selected node will be called.
+* @param: preserve - preserve earlier selected nodes
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype.selectItem=function(itemId,mode,preserve){
+ mode=convertStringToBoolean(mode);
+ var temp=this._globalIdStorageFind(itemId);
+ if ((!temp)||(!temp.parentObject)) return 0;
+
+ if (this.XMLloadingWarning)
+ temp.parentObject.openMe=1;
+ else
+ this._openItem(temp.parentObject);
+
+ //temp.onRowSelect(0,temp.htmlNode.childNodes[0].childNodes[0].childNodes[3],mode);
+ var ze=null;
+ if (preserve) {
+ ze=new Object; ze.ctrlKey=true;
+ if (temp.i_sel) ze.skipUnSel=true;
+ }
+ if (mode)
+ this.onRowSelect(ze,temp.htmlNode.childNodes[0].childNodes[0].childNodes[3],false);
+ else
+ this.onRowSelect(ze,temp.htmlNode.childNodes[0].childNodes[0].childNodes[3],true);
+ };
+
+/**
+* @desc: retun selected node text
+* @type: public
+* @return: text of selected node (or list of all selected nodes text if more than one selected)
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype.getSelectedItemText=function()
+ {
+ var str=new Array();
+ for (var i=0; i<this._selected.length; i++) str[i]=this._selected[i].span.innerHTML;
+ return (str.join(this.dlmtr));
+ };
+
+
+
+
+/**
+* @desc: correct childNode list after node deleting
+* @type: private
+* @param: Count - childNodes collection length
+* @param: Nodes - childNodes collection
+* @topic: 4
+*/
+ dhtmlXTreeObject.prototype._compressChildList=function(Count,Nodes)
+ {
+ Count--;
+ for (var i=0; i<Count; i++)
+ {
+ if (Nodes[i]==0) { Nodes[i]=Nodes[i+1]; Nodes[i+1]=0;}
+ };
+ };
+/**
+* @desc: delete node
+* @type: private
+* @param: itemId - target node id
+* @param: htmlObject - target node object
+* @param: skip - node unregistration mode (optional, used by private methods)
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype._deleteNode=function(itemId,htmlObject,skip){
+ if ((!htmlObject)||(!htmlObject.parentObject)) return 0;
+ var tempos=0; var tempos2=0;
+ if (htmlObject.tr.nextSibling) tempos=htmlObject.tr.nextSibling.nodem;
+ if (htmlObject.tr.previousSibling) tempos2=htmlObject.tr.previousSibling.nodem;
+
+ var sN=htmlObject.parentObject;
+ var Count=sN.childsCount;
+ var Nodes=sN.childNodes;
+ for (var i=0; i<Count; i++)
+ {
+ if (Nodes[i].id==itemId) {
+ if (!skip) sN.htmlNode.childNodes[0].removeChild(Nodes[i].tr);
+ Nodes[i]=0;
+ break;
+ }
+ }
+ this._compressChildList(Count,Nodes);
+ if (!skip) {
+ sN.childsCount--;
+ }
+
+ if (tempos) {
+ this._correctPlus(tempos);
+ this._correctLine(tempos);
+ }
+ if (tempos2) {
+ this._correctPlus(tempos2);
+ this._correctLine(tempos2);
+ }
+ if (this.tscheck) this._correctCheckStates(sN);
+
+ if (!skip) {
+ this._globalIdStorageRecSub(htmlObject);
+ }
+ };
+/**
+* @desc: set state of node's checkbox
+* @type: public
+* @param: itemId - target node id
+* @param: state - checkbox state (0/1/"unsure")
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.setCheck=function(itemId,state){
+ var sNode=this._globalIdStorageFind(itemId,0,1);
+ if (!sNode) return;
+
+ if (state==="unsure")
+ this._setCheck(sNode,state);
+ else
+ {
+ state=convertStringToBoolean(state);
+ if ((this.tscheck)&&(this.smcheck)) this._setSubChecked(state,sNode);
+ else this._setCheck(sNode,state);
+ }
+ if (this.smcheck)
+ this._correctCheckStates(sNode.parentObject);
+ };
+
+ dhtmlXTreeObject.prototype._setCheck=function(sNode,state){
+ if (!sNode) return;
+ if (((sNode.parentObject._r_logic)||(this._frbtr))&&(state))
+ if (this._frbtrs){
+ if (this._frbtrL) this._setCheck(this._frbtrL,0);
+ this._frbtrL=sNode;
+ } else
+ for (var i=0; i<sNode.parentObject.childsCount; i++)
+ this._setCheck(sNode.parentObject.childNodes[i],0);
+
+ var z=sNode.htmlNode.childNodes[0].childNodes[0].childNodes[1].childNodes[0];
+
+ if (state=="unsure") sNode.checkstate=2;
+ else if (state) sNode.checkstate=1; else sNode.checkstate=0;
+ if (sNode.dscheck) sNode.checkstate=sNode.dscheck;
+ this._setSrc(z,this.imPath+((sNode.parentObject._r_logic||this._frbtr)?this.radioArray:this.checkArray)[sNode.checkstate]);
+ };
+
+/**
+* @desc: change state of node's checkbox and all children checkboxes
+* @type: public
+* @param: itemId - target node id
+* @param: state - checkbox state
+* @topic: 5
+*/
+dhtmlXTreeObject.prototype.setSubChecked=function(itemId,state){
+ var sNode=this._globalIdStorageFind(itemId);
+ this._setSubChecked(state,sNode);
+ this._correctCheckStates(sNode.parentObject);
+}
+
+
+
+/**
+* @desc: change state of node's checkbox and all childnodes checkboxes
+* @type: private
+* @param: itemId - target node id
+* @param: state - checkbox state
+* @param: sNode - target node object (optional, used by private methods)
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype._setSubChecked=function(state,sNode){
+ state=convertStringToBoolean(state);
+ if (!sNode) return;
+ if (((sNode.parentObject._r_logic)||(this._frbtr))&&(state))
+ for (var i=0; i<sNode.parentObject.childsCount; i++)
+ this._setSubChecked(0,sNode.parentObject.childNodes[i]);
+
+
+ if (sNode._r_logic||this._frbtr)
+ this._setSubChecked(state,sNode.childNodes[0]);
+ else
+ for (var i=0; i<sNode.childsCount; i++)
+ {
+ this._setSubChecked(state,sNode.childNodes[i]);
+ };
+ var z=sNode.htmlNode.childNodes[0].childNodes[0].childNodes[1].childNodes[0];
+
+ if (state) sNode.checkstate=1;
+ else sNode.checkstate=0;
+ if (sNode.dscheck) sNode.checkstate=sNode.dscheck;
+
+
+
+ this._setSrc(z,this.imPath+((sNode.parentObject._r_logic||this._frbtr)?this.radioArray:this.checkArray)[sNode.checkstate]);
+ };
+
+/**
+* @desc: get state of nodes's checkbox
+* @type: public
+* @param: itemId - target node id
+* @return: node state (0 - unchecked,1 - checked, 2 - third state)
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.isItemChecked=function(itemId){
+ var sNode=this._globalIdStorageFind(itemId);
+ if (!sNode) return;
+ return sNode.checkstate;
+ };
+
+
+
+
+
+
+
+/**
+* @desc: delete all children of node
+* @type: public
+* @param: itemId - node id
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.deleteChildItems=function(itemId)
+ {
+ var sNode=this._globalIdStorageFind(itemId);
+ if (!sNode) return;
+ var j=sNode.childsCount;
+ for (var i=0; i<j; i++)
+ {
+ this._deleteNode(sNode.childNodes[0].id,sNode.childNodes[0]);
+ };
+ };
+
+/**
+* @desc: delete node
+* @type: public
+* @param: itemId - node id
+* @param: selectParent - If true parent of deleted item get selection, else no selected items leaving in tree.
+* @topic: 2
+*/
+dhtmlXTreeObject.prototype.deleteItem=function(itemId,selectParent){
+ if ((!this._onrdlh)||(this._onrdlh(itemId))){
+ var z=this._deleteItem(itemId,selectParent);
+
+ }
+
+ //nb:solves standard doctype prb in IE
+ this.allTree.childNodes[0].border = "1";
+ this.allTree.childNodes[0].border = "0";
+}
+/**
+* @desc: delete node
+* @type: private
+* @param: id - node id
+* @param: selectParent - If true parent of deleted item get selection, else no selected items leaving in tree.
+* @param: skip - unregistering mode (optional, used by private methods)
+* @topic: 2
+*/
+dhtmlXTreeObject.prototype._deleteItem=function(itemId,selectParent,skip){
+ selectParent=convertStringToBoolean(selectParent);
+ var sNode=this._globalIdStorageFind(itemId);
+ if (!sNode) return;
+ var pid=this.getParentId(itemId);
+
+ var zTemp=sNode.parentObject;
+ this._deleteNode(itemId,sNode,skip);
+ this._correctPlus(zTemp);
+ this._correctLine(zTemp);
+
+ if ((selectParent)&&(pid!=this.rootId)) this.selectItem(pid,1);
+ return zTemp;
+ };
+
+/**
+* @desc: uregister all child nodes of target node
+* @type: private
+* @param: itemObject - node object
+* @topic: 3
+*/
+ dhtmlXTreeObject.prototype._globalIdStorageRecSub=function(itemObject){
+ for(var i=0; i<itemObject.childsCount; i++)
+ {
+ this._globalIdStorageRecSub(itemObject.childNodes[i]);
+ this._globalIdStorageSub(itemObject.childNodes[i].id);
+ };
+ this._globalIdStorageSub(itemObject.id);
+
+ /*anti memory leaking*/
+ var z=itemObject;
+// var par=z.span.parentNode.parentNode.childNodes;
+// par[0].parentObject=null;
+// par[1].childNodes[0].parentObject=null;
+// par[2].childNodes[0].parentObject=null;
+// par[2].childNodes[0].treeNod=null;
+// par[2].parentObject=null;
+// par[3].parentObject=null;
+ z.span=null;
+ z.tr.nodem=null;
+ z.tr=null;
+ z.htmlNode=null;
+ };
+
+/**
+* @desc: create new node next to specified
+* @type: public
+* @param: itemId - node id
+* @param: newItemId - new node id
+* @param: itemText - new node text
+* @param: itemActionHandler - function fired on node select event (optional)
+* @param: image1 - image for node without children; (optional)
+* @param: image2 - image for closed node; (optional)
+* @param: image3 - image for opened node (optional)
+* @param: optionStr - options string (optional)
+* @param: children - node children flag (for dynamical trees) (optional)
+* @topic: 2
+*/
+ dhtmlXTreeObject.prototype.insertNewNext=function(itemId,newItemId,itemText,itemActionHandler,image1,image2,image3,optionStr,children){
+ var sNode=this._globalIdStorageFind(itemId);
+ if ((!sNode)||(!sNode.parentObject)) return (0);
+
+ var nodez=this._attachChildNode(0,newItemId,itemText,itemActionHandler,image1,image2,image3,optionStr,children,sNode);
+
+ return nodez;
+ };
+
+
+
+/**
+* @desc: retun node id by index
+* @type: public
+* @param: itemId - parent node id
+* @param: index - index of node, 0 based
+* @return: node id
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype.getItemIdByIndex=function(itemId,index){
+ var z=this._globalIdStorageFind(itemId);
+ if ((!z)||(index>z.childsCount)) return null;
+ return z.childNodes[index].id;
+ };
+
+/**
+* @desc: retun child node id by index
+* @type: public
+* @param: itemId - parent node id
+* @param: index - index of child node
+* @return: node id
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype.getChildItemIdByIndex=function(itemId,index){
+ var z=this._globalIdStorageFind(itemId);
+ if ((!z)||(index>=z.childsCount)) return null;
+ return z.childNodes[index].id;
+ };
+
+
+
+
+
+/**
+* @desc: set function called when drag-and-drop event occured
+* @param: aFunc - event handling function
+* @type: deprecated
+* @topic: 0,7
+* @event: onDrag
+* @depricated: use grid.attachEvent("onDrag",func); instead
+* @eventdesc: Event occured after item was dragged and droped on another item, but before item moving processed.
+ Event also raised while programmatic moving nodes.
+* @eventparam: ID of source item
+* @eventparam: ID of target item
+* @eventparam: if node droped as sibling then contain id of item before whitch source node will be inserted
+* @eventparam: source Tree object
+* @eventparam: target Tree object
+* @eventreturn: true - confirm drag-and-drop; false - deny drag-and-drop;
+*/
+ dhtmlXTreeObject.prototype.setDragHandler=function(func){ this.attachEvent("onDrag",func); };
+
+ /**
+* @desc: clear selection from node
+* @param: htmlNode - pointer to node object
+* @type: private
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype._clearMove=function(){
+ if (this._lastMark){
+ this._lastMark.className=this._lastMark.className.replace(/dragAndDropRow/g,"");
+ this._lastMark=null;
+ }
+
+ this.allTree.className=this.allTree.className.replace(" selectionBox","");
+ };
+
+ /**
+* @desc: enable/disable drag-and-drop
+* @type: public
+* @param: mode - enabled/disabled [ can be true/false/temporary_disabled - last value mean that tree can be D-n-D can be switched to true later ]
+* @param: rmode - enabled/disabled drag and drop on super root
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableDragAndDrop=function(mode,rmode){
+ if (mode=="temporary_disabled"){
+ this.dADTempOff=false;
+ mode=true; }
+ else
+ this.dADTempOff=true;
+
+ this.dragAndDropOff=convertStringToBoolean(mode);
+ if (this.dragAndDropOff) this.dragger.addDragLanding(this.allTree,this);
+ if (arguments.length>1)
+ this._ddronr=(!convertStringToBoolean(rmode));
+ };
+
+/**
+* @desc: set selection on node
+* @param: node - pointer to node object
+* @type: private
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype._setMove=function(htmlNode,x,y){
+ if (htmlNode.parentObject.span) {
+ //window.status=x;
+ var a1=getAbsoluteTop(htmlNode);
+ var a2=getAbsoluteTop(this.allTree);
+
+ this.dadmodec=this.dadmode;//this.dadmode;
+ this.dadmodefix=0;
+
+
+ var zN=htmlNode.parentObject.span;
+ zN.className+=" dragAndDropRow";
+ this._lastMark=zN;
+
+ this._autoScroll(null,a1,a2);
+
+ }
+ };
+
+dhtmlXTreeObject.prototype._autoScroll=function(node,a1,a2){
+ if (this.autoScroll)
+ {
+ if (node){
+ a1=getAbsoluteTop(node);
+ a2=getAbsoluteTop(this.allTree);
+ }
+ //scroll down
+ if ( (a1-a2-parseInt(this.allTree.scrollTop))>(parseInt(this.allTree.offsetHeight)-50) )
+ this.allTree.scrollTop=parseInt(this.allTree.scrollTop)+20;
+ //scroll top
+ if ( (a1-a2)<(parseInt(this.allTree.scrollTop)+30) )
+ this.allTree.scrollTop=parseInt(this.allTree.scrollTop)-20;
+ }
+}
+
+/**
+* @desc: create html element for dragging
+* @type: private
+* @param: htmlObject - html node object
+* @topic: 1
+*/
+dhtmlXTreeObject.prototype._createDragNode=function(htmlObject,e){
+ if (!this.dADTempOff) return null;
+
+ var obj=htmlObject.parentObject;
+ if (!this.callEvent("onBeforeDrag",[obj.id])) return null;
+ if (!obj.i_sel)
+ this._selectItem(obj,e);
+
+
+ var dragSpan=document.createElement('div');
+
+ var text=new Array();
+ if (this._itim_dg)
+ for (var i=0; i<this._selected.length; i++)
+ text[i]="<table cellspacing='0' cellpadding='0'><tr><td><img width='18px' height='18px' src='"+this._getSrc(this._selected[i].span.parentNode.previousSibling.childNodes[0])+"'></td><td>"+this._selected[i].span.innerHTML+"</td></tr><table>";
+ else
+ text=this.getSelectedItemText().split(this.dlmtr);
+
+ dragSpan.innerHTML=text.join("");
+ dragSpan.style.position="absolute";
+ dragSpan.className="dragSpanDiv";
+ this._dragged=(new Array()).concat(this._selected);
+ return dragSpan;
+}
+
+
+
+/**
+* @desc: focus item in tree
+* @type: private
+* @param: item - node object
+* @edition: Professional
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype._focusNode=function(item){
+ var z=getAbsoluteTop(item.htmlNode)-getAbsoluteTop(this.allTree);
+ if ((z>(this.allTree.scrollTop+this.allTree.offsetHeight-30))||(z<this.allTree.scrollTop))
+ this.allTree.scrollTop=z;
+ };
+
+
+
+
+
+
+
+
+
+
+
+
+
+///DragAndDrop
+
+dhtmlXTreeObject.prototype._preventNsDrag=function(e){
+ if ((e)&&(e.preventDefault)) { e.preventDefault(); return false; }
+ return false;
+}
+
+dhtmlXTreeObject.prototype._drag=function(sourceHtmlObject,dhtmlObject,targetHtmlObject){
+ if (this._autoOpenTimer) clearTimeout(this._autoOpenTimer);
+
+ if (!targetHtmlObject.parentObject){
+ targetHtmlObject=this.htmlNode.htmlNode.childNodes[0].childNodes[0].childNodes[1].childNodes[0];
+ this.dadmodec=0;
+ }
+
+ this._clearMove();
+ var z=sourceHtmlObject.parentObject.treeNod;
+ if ((z)&&(z._clearMove)) z._clearMove("");
+
+ if ((!this.dragMove)||(this.dragMove()))
+ {
+ if ((!z)||(!z._clearMove)||(!z._dragged)) var col=new Array(sourceHtmlObject.parentObject);
+ else var col=z._dragged;
+ var trg=targetHtmlObject.parentObject;
+
+ for (var i=0; i<col.length; i++){
+ var newID=this._moveNode(col[i],trg);
+ if ((this.dadmodec)&&(newID!==false)) trg=this._globalIdStorageFind(newID,true,true);
+ if ((newID)&&(!this._sADnD)) this.selectItem(newID,0,1);
+ }
+
+ }
+ if (z) z._dragged=new Array();
+
+
+}
+
+dhtmlXTreeObject.prototype._dragIn=function(htmlObject,shtmlObject,x,y){
+
+ if (!this.dADTempOff) return 0;
+ var fobj=shtmlObject.parentObject;
+ var tobj=htmlObject.parentObject;
+ if ((!tobj)&&(this._ddronr)) return;
+ if (!this.callEvent("onDragIn",[fobj.id,tobj?tobj.id:null,fobj.treeNod,this]))
+ return 0;
+
+ if (!tobj)
+ this.allTree.className+=" selectionBox";
+ else
+ {
+ if (fobj.childNodes==null){
+ this._setMove(htmlObject,x,y);
+ return htmlObject;
+ }
+
+ var stree=fobj.treeNod;
+ for (var i=0; i<stree._dragged.length; i++)
+ if (this._checkPNodes(tobj,stree._dragged[i])){
+ this._autoScroll(htmlObject);
+ return 0;
+ }
+
+ this._setMove(htmlObject,x,y);
+ if (this._getOpenState(tobj)<=0){
+ this._autoOpenId=tobj.id;
+ this._autoOpenTimer=window.setTimeout(new callerFunction(this._autoOpenItem,this),1000);
+ }
+ }
+
+ return htmlObject;
+
+}
+dhtmlXTreeObject.prototype._autoOpenItem=function(e,treeObject){
+ treeObject.openItem(treeObject._autoOpenId);
+};
+dhtmlXTreeObject.prototype._dragOut=function(htmlObject){
+this._clearMove();
+if (this._autoOpenTimer) clearTimeout(this._autoOpenTimer);
+ }
+
+
+
+
+
+//#complex_move:01112006{
+
+/**
+* @desc: move item (inside of tree)
+* @type: public
+* @param: itemId - item Id
+* @param: mode - moving mode (left,up,down,item_child,item_sibling,item_sibling_next,up_strict,down_strict)
+* @param: targetId - target Node in item_child and item_sibling mode
+* @param: targetTree - used for moving between trees (optional)
+* @return: node id
+* @topic: 2
+*/
+dhtmlXTreeObject.prototype.moveItem=function(itemId,mode,targetId,targetTree)
+{
+ var sNode=this._globalIdStorageFind(itemId);
+ if (!sNode) return (0);
+
+ switch(mode){
+ case "right": alert('Not supported yet');
+ break;
+ case "item_child":
+ var tNode=(targetTree||this)._globalIdStorageFind(targetId);
+ if (!tNode) return (0);
+ (targetTree||this)._moveNodeTo(sNode,tNode,0);
+ break;
+ case "item_sibling":
+ var tNode=(targetTree||this)._globalIdStorageFind(targetId);
+ if (!tNode) return (0);
+ (targetTree||this)._moveNodeTo(sNode,tNode.parentObject,tNode);
+ break;
+ case "item_sibling_next":
+ var tNode=(targetTree||this)._globalIdStorageFind(targetId);
+ if (!tNode) return (0);
+ if ((tNode.tr)&&(tNode.tr.nextSibling)&&(tNode.tr.nextSibling.nodem))
+ (targetTree||this)._moveNodeTo(sNode,tNode.parentObject,tNode.tr.nextSibling.nodem);
+ else
+ (targetTree||this)._moveNodeTo(sNode,tNode.parentObject);
+ break;
+ case "left": if (sNode.parentObject.parentObject)
+ this._moveNodeTo(sNode,sNode.parentObject.parentObject,sNode.parentObject);
+ break;
+ case "up": var z=this._getPrevNode(sNode);
+ if ((z==-1)||(!z.parentObject)) return;
+ this._moveNodeTo(sNode,z.parentObject,z);
+ break;
+ case "up_strict": var z=this._getIndex(sNode);
+ if (z!=0)
+ this._moveNodeTo(sNode,sNode.parentObject,sNode.parentObject.childNodes[z-1]);
+ break;
+ case "down_strict": var z=this._getIndex(sNode);
+ var count=sNode.parentObject.childsCount-2;
+ if (z==count)
+ this._moveNodeTo(sNode,sNode.parentObject);
+ else if (z<count)
+ this._moveNodeTo(sNode,sNode.parentObject,sNode.parentObject.childNodes[z+2]);
+ break;
+ case "down": var z=this._getNextNode(this._lastChild(sNode));
+ if ((z==-1)||(!z.parentObject)) return;
+ if (z.parentObject==sNode.parentObject)
+ var z=this._getNextNode(z);
+ if (z==-1){
+ this._moveNodeTo(sNode,sNode.parentObject);
+ }
+ else
+ {
+ if ((z==-1)||(!z.parentObject)) return;
+ this._moveNodeTo(sNode,z.parentObject,z);
+ }
+ break;
+ }
+}
+
+
+//#}
+
+
+
+
+
+
+
+/**
+* @desc: load xml for tree branch
+* @param: id - id of parent node
+* @param: src - path to xml, optional
+* @type: private
+* @topic: 1
+*/
+ dhtmlXTreeObject.prototype._loadDynXML=function(id,src) {
+ src=src||this.XMLsource;
+ var sn=(new Date()).valueOf();
+ this._ld_id=id;
+
+ this.loadXML(src+getUrlSymbol(src)+"uid="+sn+"&id="+this._escape(id));
+ };
+
+
+
+
+
+
+
+/**
+* @desc: check possibility of drag-and-drop
+* @type: private
+* @param: itemId - draged node id
+* @param: htmlObject - droped node object
+* @param: shtmlObject - sourse node object
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._checkPNodes=function(item1,item2){
+ if (item2==item1) return 1
+ if (item1.parentObject) return this._checkPNodes(item1.parentObject,item2); else return 0;
+ };
+
+
+
+
+
+
+
+
+
+
+/**
+* @desc: prevent caching in IE by adding random value to URL string
+* @param: mode - enable/disable random value ( disabled by default )
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.preventIECaching=function(mode){
+ this.no_cashe = convertStringToBoolean(mode);
+ this.XMLLoader.rSeed=this.no_cashe;
+}
+dhtmlXTreeObject.prototype.preventIECashing=dhtmlXTreeObject.prototype.preventIECaching;
+
+
+
+
+//#tree_extra:01112006{
+
+/**
+* @desc: disable checkbox
+* @param: itemId - Id of tree item
+* @param: mode - 1 - on, 0 - off;
+* @type: public
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.disableCheckbox=function(itemId,mode) {
+ if (typeof(itemId)!="object")
+ var sNode=this._globalIdStorageFind(itemId,0,1);
+ else
+ var sNode=itemId;
+ if (!sNode) return;
+ sNode.dscheck=convertStringToBoolean(mode)?(((sNode.checkstate||0)%3)+3):((sNode.checkstate>2)?(sNode.checkstate-3):sNode.checkstate);
+ this._setCheck(sNode);
+ if (sNode.dscheck<3) sNode.dscheck=false;
+ };
+
+
+
+
+/**
+* @desc: set escaping mode (used for escaping ID in requests)
+* @param: mode - escaping mode ("utf8" for UTF escaping)
+* @type: public
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.setEscapingMode=function(mode){
+ this.utfesc=mode;
+ }
+
+
+/**
+* @desc: enable item highlighting (item text highlited on mouseover)
+* @beforeInit: 1
+* @param: mode - 1 - on, 0 - off;
+* @type: public
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableHighlighting=function(mode) { this.ehlt=true; this.ehlta=convertStringToBoolean(mode); };
+
+/**
+* @desc: called on mouse out
+* @type: private
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype._itemMouseOut=function(){
+ var that=this.childNodes[3].parentObject;
+ var tree=that.treeNod;
+ tree.callEvent("onMouseOut",[that.id]);
+ if (that.id==tree._l_onMSI) tree._l_onMSI=null;
+ if (!tree.ehlta) return;
+ that.span.className=that.span.className.replace("_lor","");
+ }
+/**
+* @desc: called on mouse in
+* @type: private
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype._itemMouseIn=function(){
+ var that=this.childNodes[3].parentObject;
+ var tree=that.treeNod;
+
+ if (tree._l_onMSI!=that.id) tree.callEvent("onMouseIn",[that.id]);
+ tree._l_onMSI=that.id;
+ if (!tree.ehlta) return;
+ that.span.className=that.span.className.replace("_lor","");
+ that.span.className=that.span.className.replace(/((standart|selected)TreeRow)/,"$1_lor");
+ }
+
+/**
+* @desc: enable active images (clickable and dragable). By default only text part of the node is active
+* @beforeInit: 1
+* @param: mode - 1 - on, 0 - off;
+* @type: public
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableActiveImages=function(mode){this._aimgs=convertStringToBoolean(mode); };
+
+/**
+* @desc: focus item in tree (scroll to it if necessary)
+* @type: public
+* @param: itemId - item Id
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.focusItem=function(itemId){
+ var sNode=this._globalIdStorageFind(itemId);
+ if (!sNode) return (0);
+ this._focusNode(sNode);
+ };
+
+
+/**
+* @desc: Returns the list of all children from all next levels of tree, separated by default delimiter.
+* @param: itemId - id of node
+* @type: public
+* @return: list of all children items from all next levels of tree, separated by default delimiter
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.getAllSubItems =function(itemId){
+ return this._getAllSubItems(itemId);
+ }
+
+/**
+* @desc: Returns the list of all items which doesn't have child nodes.
+* @type: public
+* @return: list of all items which doesn't have child nodes.
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.getAllChildless =function(){
+ return this._getAllScraggyItems(this.htmlNode);
+ }
+ dhtmlXTreeObject.prototype.getAllLeafs=dhtmlXTreeObject.prototype.getAllChildless;
+
+
+/**
+* @desc: Returns the list of all children from all next levels of tree, separated by default delimiter.
+* @param: itemId - id of node
+* @edition: Professional
+* @type: private
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._getAllScraggyItems =function(node)
+ {
+ var z="";
+ for (var i=0; i<node.childsCount; i++)
+ {
+ if ((node.childNodes[i].unParsed)||(node.childNodes[i].childsCount>0))
+ {
+ if (node.childNodes[i].unParsed)
+ var zb=this._getAllScraggyItemsXML(node.childNodes[i].unParsed,1);
+ else
+ var zb=this._getAllScraggyItems(node.childNodes[i])
+
+ if (zb)
+ if (z) z+=this.dlmtr+zb;
+ else z=zb;
+ }
+ else
+ if (!z) z=node.childNodes[i].id;
+ else z+=this.dlmtr+node.childNodes[i].id;
+ }
+ return z;
+ };
+
+
+
+
+
+/**
+* @desc: Returns the list of all children from all next levels of tree, separated by default delimiter.
+* @param: itemId - id of node
+* @type: private
+* @edition: Professional
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype._getAllFatItems =function(node)
+ {
+ var z="";
+ for (var i=0; i<node.childsCount; i++)
+ {
+ if ((node.childNodes[i].unParsed)||(node.childNodes[i].childsCount>0))
+ {
+ if (!z) z=node.childNodes[i].id;
+ else z+=this.dlmtr+node.childNodes[i].id;
+
+ if (node.childNodes[i].unParsed)
+ var zb=this._getAllFatItemsXML(node.childNodes[i].unParsed,1);
+ else
+ var zb=this._getAllFatItems(node.childNodes[i])
+
+ if (zb) z+=this.dlmtr+zb;
+ }
+ }
+ return z;
+ };
+
+/**
+* @desc: Returns the list of all items which have child nodes, separated by default delimiter.
+* @type: public
+* @return: list of all items which has child nodes, separated by default delimiter.
+* @topic: 6
+*/
+ dhtmlXTreeObject.prototype.getAllItemsWithKids =function(){
+ return this._getAllFatItems(this.htmlNode);
+ }
+ dhtmlXTreeObject.prototype.getAllFatItems=dhtmlXTreeObject.prototype.getAllItemsWithKids;
+
+
+
+/**
+* @desc: return list of identificators of nodes with checked checkboxes, separated by default delimiter
+* @type: public
+* @return: list of ID of items with checked checkboxes, separated by default delimiter
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.getAllChecked=function(){
+ return this._getAllChecked("","",1);
+ }
+/**
+* @desc: return list of identificators of nodes with unchecked checkboxes, separated by default delimiter
+* @type: public
+* @return: list of ID of items with unchecked checkboxes, separated by default delimiter
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.getAllUnchecked=function(itemId){
+ if (itemId)
+ itemId=this._globalIdStorageFind(itemId);
+ return this._getAllChecked(itemId,"",0);
+ }
+
+
+/**
+* @desc: return list of identificators of nodes with third state checkboxes, separated by default delimiter
+* @type: public
+* @return: list of ID of items with third state checkboxes, separated by default delimiter
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.getAllPartiallyChecked=function(){
+ return this._getAllChecked("","",2);
+ }
+
+
+/**
+* @desc: return list of identificators of nodes with checked and third state checkboxes, separated by default delimiter
+* @type: public
+* @return: list of ID of items with checked and third state checkboxes, separated by default delimiter
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype.getAllCheckedBranches=function(){
+ var temp= this._getAllChecked("","",1);
+ if (temp!="") temp+=this.dlmtr;
+ return temp+this._getAllChecked("","",2);
+ }
+
+/**
+* @desc: return list of identificators of nodes with checked checkboxes
+* @type: private
+* @param: node - node object (optional, used by private methods)
+* @param: list - initial identificators list (optional, used by private methods)
+* @topic: 5
+*/
+ dhtmlXTreeObject.prototype._getAllChecked=function(htmlNode,list,mode){
+ if (!htmlNode) htmlNode=this.htmlNode;
+
+ if (htmlNode.checkstate==mode)
+ if (!htmlNode.nocheckbox) { if (list) list+=this.dlmtr+htmlNode.id; else list=htmlNode.id; }
+ var j=htmlNode.childsCount;
+ for (var i=0; i<j; i++)
+ {
+ list=this._getAllChecked(htmlNode.childNodes[i],list,mode);
+ };
+
+
+ if (list) return list; else return "";
+ };
+
+/**
+* @desc: set individual item style
+* @type: public
+* @param: itemId - node id
+* @param: style_string - valid CSS string
+* @topic: 2
+*/
+dhtmlXTreeObject.prototype.setItemStyle=function(itemId,style_string){
+ var temp=this._globalIdStorageFind(itemId);
+ if (!temp) return 0;
+ if (!temp.span.style.cssText)
+ temp.span.setAttribute("style",temp.span.getAttribute("style")+"; "+style_string);
+ else
+ temp.span.style.cssText+=(";"+style_string);
+}
+
+/**
+* @desc: enable draging item image with item text
+* @type: public
+* @param: mode - true/false
+* @topic: 1
+*/
+dhtmlXTreeObject.prototype.enableImageDrag=function(mode){
+ this._itim_dg=convertStringToBoolean(mode);
+}
+
+/**
+* @desc: set function called when tree item draged over another item
+* @param: func - event handling function
+* @type: depricated
+* @edition: Professional
+* @topic: 4
+* @event: onDragIn
+* @depricated: use grid.attachEvent("onDragIn",func); instead
+* @eventdesc: Event raised when item draged other other dropable target
+* @eventparam: ID draged item
+* @eventparam: ID potencial drop landing
+* @eventparam: source object
+* @eventparam: target object
+* @eventreturn: true - allow drop; false - deny drop;
+*/
+ dhtmlXTreeObject.prototype.setOnDragIn=function(func){
+ this.attachEvent("onDragIn",func);
+ };
+
+/**
+* @desc: enable/disable auto scrolling while drag-and-drop
+* @type: public
+* @param: mode - enabled/disabled
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.enableDragAndDropScrolling=function(mode){ this.autoScroll=convertStringToBoolean(mode); };
+//#}
+
+
+dhtmlXTreeObject.prototype.dhx_Event=function()
+{
+ this.dhx_SeverCatcherPath="";
+
+ this.attachEvent = function(original, catcher, CallObj)
+ {
+ if (this._onEventSet && this._onEventSet[original])
+ this._onEventSet[original].apply(this,[]);
+
+ CallObj = CallObj||this;
+ original = 'ev_'+original;
+ if ( ( !this[original] ) || ( !this[original].addEvent ) ) {
+ var z = new this.eventCatcher(CallObj);
+ z.addEvent( this[original] );
+ this[original] = z;
+ }
+ return ( original + ':' + this[original].addEvent(catcher) ); //return ID (event name & event ID)
+ }
+ this.callEvent=function(name,a){
+ if (this["ev_"+name]) return this["ev_"+name].apply(this,a);
+ return true;
+ }
+ this.checkEvent=function(name){
+ if (this["ev_"+name]) return true;
+ return false;
+ }
+
+ this.eventCatcher = function(obj)
+ {
+ var dhx_catch = new Array();
+ var m_obj = obj;
+ var func_server = function(catcher,rpc)
+ {
+ catcher = catcher.split(":");
+ var postVar="";
+ var postVar2="";
+ var target=catcher[1];
+ if (catcher[1]=="rpc"){
+ postVar='<?xml version="1.0"?><methodCall><methodName>'+catcher[2]+'</methodName><params>';
+ postVar2="</params></methodCall>";
+ target=rpc;
+ }
+ var z = function() {
+ var loader = new dtmlXMLLoaderObject( null, window, false );
+ var request=postVar;
+ if (postVar2){
+ for (var i=0; i<arguments.length; i++)
+ request += "<param><value><string>"+(arguments[i]?arguments[i].toString():"")+"</string></value></param>";
+ request+=postVar2;
+ }
+ else
+ for (var i=0; i<arguments.length; i++)
+ request += ( '&arg'+i+'='+escape(arguments[i]));
+
+ loader.loadXML( target, true, request,postVar2?true:false);
+
+ try{
+ if (postVar2){
+ var dt=loader.doXPath("//methodResponse/params/param/value/string");
+ return convertStringToBoolean(dt[0].firstChild.data);
+ }
+ else return convertStringToBoolean(loader.xmlDoc.responseText);
+ }
+ catch(e){
+
+ dhtmlxError.throwError("rpcError",loader.xmlDoc.responseText);
+ return false;
+ }
+ }
+ return z;
+ }
+ var z = function()
+ {
+ if (dhx_catch)
+ var res=true;
+ for (var i=0; i<dhx_catch.length; i++) {
+ if (dhx_catch[i] != null) {
+ var zr = dhx_catch[i].apply( m_obj, arguments );
+ res = res && zr;
+ }
+ }
+ return res;
+ }
+ z.addEvent = function(ev)
+ {
+ if ( typeof(ev) != "function" )
+ if (ev && ev.indexOf && ev.indexOf("server:") === 0)
+ ev = new func_server(ev,m_obj.rpcServer);
+ else
+ ev = eval(ev);
+ if (ev)
+ return dhx_catch.push( ev ) - 1;
+ return false;
+ }
+ z.removeEvent = function(id)
+ {
+ dhx_catch[id] = null;
+ }
+ return z;
+ }
+
+ this.detachEvent = function(id)
+ {
+ if (id != false) {
+ var list = id.split(':'); //get EventName and ID
+ this[ list[0] ].removeEvent( list[1] ); //remove event
+ }
+ }
+}
+//(c)dhtmlx ltd. www.dhtmlx.com \ No newline at end of file
diff --git a/funcweb/funcweb/static/javascript/ext/dhtmlxtree_dragin.js b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_dragin.js
new file mode 100644
index 0000000..3de7a72
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_dragin.js
@@ -0,0 +1,75 @@
+//v.1.6 build 80512
+
+/*
+Copyright DHTMLX LTD. http://www.dhtmlx.com
+You allowed to use this component or parts of it under GPL terms
+To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
+*/
+/**
+* @desc: adds drag-n-drop capabilities (with possibility to drop into dhtmlxTree) to HTML object.
+* @param: obj - HTML object, or HTML object ID
+* @param: func - custom drag processor function, optional
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.makeDragable=function(obj,func){
+ if (typeof(obj)!="object")
+ obj=document.getElementById(obj);
+
+ dragger=new dhtmlDragAndDropObject();
+ dropper=new dhx_dragSomethingInTree();
+
+ dragger.addDraggableItem(obj,dropper);
+ obj.dragLanding=null;
+ obj.ondragstart=dropper._preventNsDrag;
+ obj.onselectstart=new Function("return false;");
+
+ obj.parentObject=new Object;
+ obj.parentObject.img=obj;
+ obj.parentObject.treeNod=dropper;
+ dropper._customDrop=func;
+}
+/**
+* @desc: adds drag-n-drop capabilities (with possibility to drop into dhtmlxTree) to all HTML items with dragInDhtmlXTree attribute
+* @param: func - custom drag processor function, optional
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.makeAllDraggable=function(func){
+ var z=document.getElementsByTagName("div");
+ for (var i=0; i<z.length; i++)
+ if (z[i].getAttribute("dragInDhtmlXTree"))
+ this.makeDragable(z[i],func);
+}
+
+function dhx_dragSomethingInTree(){
+ this.lWin=window;
+ //this function creates a HTML object which will be used while drag-n-drop
+ this._createDragNode=function(node){
+ var dragSpan=document.createElement('div');
+ dragSpan.style.position="absolute";
+ dragSpan.innerHTML=node.innerHTML;
+ dragSpan.style.zIndex=12;
+ return dragSpan;
+ };
+ //this function necessary for correct browser support
+ //doesn't change anything in it
+ this._preventNsDrag=function(e){
+ (e||window.event).cancelBubble=true;
+ if ((e)&&(e.preventDefault)) { e.preventDefault(); return false; }
+ return false;
+ }
+ //this function contains a reaction on drop operation
+ //the tree don't know what to do with custom item
+ //so you must define this reaction
+ this._nonTrivialNode=function(tree,item,bitem,source){
+ if (this._customDrop) return this._customDrop(tree,source.img.id,item.id,bitem?bitem.id:null);
+
+ var image=(source.img.getAttribute("image")||"");
+ var id=source.img.id||"new";
+ var text=(source.img.getAttribute("text")||(_isIE?source.img.innerText:source.img.textContent));
+ if (tree.callEvent("onDrag",[id,item.id,source.img,tree]))
+ tree[bitem?"insertNewNext":"insertNewItem"](bitem?bitem.id:item.id,id,text,"",image,image,image);
+ }
+}
+//(c)dhtmlx ltd. www.dhtmlx.com \ No newline at end of file
diff --git a/funcweb/funcweb/static/javascript/ext/dhtmlxtree_ed.js b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_ed.js
new file mode 100644
index 0000000..402df58
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_ed.js
@@ -0,0 +1,189 @@
+//v.1.6 build 80512
+
+/*
+Copyright DHTMLX LTD. http://www.dhtmlx.com
+You allowed to use this component or parts of it under GPL terms
+To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
+*/
+/*
+Purpose: item edit extension
+*/
+
+
+/**
+* @desc: enable editing of item text
+* @param: mode - true/false
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.enableItemEditor=function(mode){
+ this._eItEd=convertStringToBoolean(mode);
+ if (!this._eItEdFlag){
+
+ this._edn_click_IE=true;
+ this._edn_dblclick=true;
+ this._ie_aFunc=this.aFunc;
+ this._ie_dblclickFuncHandler=this.dblclickFuncHandler;
+
+ this.setOnDblClickHandler(function (a,b) {
+ if (this._edn_dblclick) this._editItem(a,b);
+ return true;
+ });
+
+ this.setOnClickHandler(function (a,b) {
+ this._stopEditItem(a,b);
+ if ((this.ed_hist_clcik==a)&&(this._edn_click_IE))
+ this._editItem(a,b);
+ this.ed_hist_clcik=a;
+ return true;
+ });
+
+ this._eItEdFlag=true;
+
+ }
+ };
+
+/**
+* @desc: set onEdit handler ( multi handler event)
+* @param: func - function which will be called on edit related events
+* @type: depricated
+* @event: onEdit
+* @depricated: use grid.attachEvent("onEdit",func); instead
+* @eventdesc: Event occurs on 4 different stages of edit process: before editing started (cancelable), after editing started, before closing (cancelable), after closed
+* @eventparam: state - 0 before editing started , 1 after editing started, 2 before closing, 3 after closed
+* @eventparam: id - id of edited items
+* @eventparam: tree - tree object
+* @eventparam: value - for stage 0 and 2, value of editor
+* @eventreturn: for stages 0 and 2; true - confirm opening/closing, false - deny opening/closing; text - edit value
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.setOnEditHandler=function(func){
+ this.attachEvent("onEdit",func);
+ };
+
+
+
+/**
+* @desc: define which events must start editing
+* @param: click_IE - click on already selected item - true/false [true by default]
+* @param: dblclick - on double click
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.setEditStartAction=function(click_IE, dblclick){
+ this._edn_click_IE=convertStringToBoolean(click_IE);
+ this._edn_dblclick=convertStringToBoolean(dblclick);
+ };
+
+dhtmlXTreeObject.prototype._stopEdit=function(a){
+ if (this._editCell){
+ this.dADTempOff=this.dADTempOffEd;
+ if (this._editCell.id!=a){
+
+ var editText=true;
+ editText=this.callEvent("onEdit",[2,this._editCell.id,this,this._editCell.span.childNodes[0].value]);
+ if (editText===true)
+ editText=this._editCell.span.childNodes[0].value;
+ else if (editText===false) editText=this._editCell._oldValue;
+
+ this._editCell.span.innerHTML=editText;
+ this._editCell.label=this._editCell.span.innerHTML;
+ var cSS=this._editCell.i_sel?"selectedTreeRow":"standartTreeRow";
+ this._editCell.span.className=cSS;
+ this._editCell.span.parentNode.className="standartTreeRow";
+ this._editCell.span.onclick=function(){};
+ var id=this._editCell.id; this._editCell=null;
+
+ if (this.childCalc) this._fixChildCountLabel(this._editCell);
+ this.callEvent("onEdit",[3,id,this]);
+
+ if (this._enblkbrd){
+ this.parentObject.lastChild.focus();
+ this.parentObject.lastChild.focus();
+ }
+ }
+ }
+}
+
+dhtmlXTreeObject.prototype._stopEditItem=function(id,tree){
+ this._stopEdit(id);
+};
+
+/**
+* @desc: switch currently edited item back to normal view
+* @type: public
+* @topic: 0
+*/
+
+dhtmlXTreeObject.prototype.stopEdit=function(){
+ if (this._editCell)
+ this._stopEdit(this._editCell.id+"_non");
+}
+
+/**
+* @desc: open editor for specified item
+* @param: id - item ID
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.editItem=function(id){
+ this._editItem(id,this);
+}
+
+dhtmlXTreeObject.prototype._editItem=function(id,tree){
+ if (this._eItEd){
+ this._stopEdit();
+ var temp=this._globalIdStorageFind(id);
+ if (!temp) return;
+
+ editText=this.callEvent("onEdit",[0,id,this,temp.span.innerHTML]);
+
+ if (editText===true)
+ editText=temp.label;
+ else if (editText===false) return;
+
+ this.dADTempOffEd=this.dADTempOff;
+ this.dADTempOff=false;
+
+
+ this._editCell=temp;
+ temp._oldValue=editText;
+ temp.span.innerHTML="<input type='text' class='intreeeditRow' />";
+
+ temp.span.childNodes[0].value=editText;
+
+ temp.span.childNodes[0].onselectstart=function(e){
+ (e||event).cancelBubble=true;
+ return true;
+ }
+ temp.span.childNodes[0].onmousedown=function(e){
+ (e||event).cancelBubble=true;
+ return true;
+ }
+
+ temp.span.childNodes[0].focus();
+ temp.span.childNodes[0].focus();
+// temp.span.childNodes[0].select();
+ temp.span.onclick=function (e){ (e||event).cancelBubble=true; return false; };
+ temp.span.className="";
+ temp.span.parentNode.className="";
+
+ var self=this;
+
+ temp.span.childNodes[0].onkeydown=function(e){
+ (e||event).cancelBubble=true;
+ }
+ temp.span.childNodes[0].onkeypress=function(e){
+ if (!e) e=window.event;
+ if (e.keyCode==13){
+ self._stopEdit(-1);
+ }
+ else if (e.keyCode==27){
+ self._editCell.span.childNodes[0].value=self._editCell._oldValue;
+ self._stopEdit(-1);
+ }
+ }
+ this.callEvent("onEdit",[1,id,this]);
+ }
+};
+//(c)dhtmlx ltd. www.dhtmlx.com
diff --git a/funcweb/funcweb/static/javascript/ext/dhtmlxtree_er.js b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_er.js
new file mode 100644
index 0000000..70d6302
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_er.js
@@ -0,0 +1,80 @@
+//v.1.6 build 80512
+
+/*
+Copyright DHTMLX LTD. http://www.dhtmlx.com
+You allowed to use this component or parts of it under GPL terms
+To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
+*/
+var _all_used_trees=new Array();
+dhtmlXTreeObject.prototype._createSelfA2=dhtmlXTreeObject.prototype._createSelf;
+dhtmlXTreeObject.prototype._createSelf=function(){
+ _all_used_trees[_all_used_trees.length]=this;
+ return this._createSelfA2();
+}
+
+window.onerror=function (a,b,c,d){
+ var d=document.createElement("DIV");
+ d.style.cssText="position:absolute; background-color:white; top:10px; left:10px; z-index:20; width:500px; border: 2px silver outset;";
+ var dh="<div style='width:100%; color:red; font-size:8pt; font-family:Arial; font-weight:bold; '>Javascript Error</div>";
+ dh+="<div style='width:100%; font-size:8pt; font-family:Arial; '>The next error ocured :<br/> <strong>"+a+"</strong> in <strong>"+b+"</strong> at line <strong>"+c+"</strong></div>";
+ dh+="<div style='width:100%; font-size:8pt; font-family:Arial; '>If you think that error can be caused by dhtmlxtree press the 'Generate report' button and send generated report to <a href='email:support@dhtmlx.com'>support@dhtmlx.com</a> </div>";
+ dh+="<input style='font-size:8pt; font-family:Arial; ' onclick='dhtmlxtreeReport(this)' type='button' value='Generate report'/><input style='font-size:8pt; font-family:Arial; ' type='button' value='Close' onclick='this.parentNode.parentNode.removeChild(this.parentNode);'/>";
+ dh+="<div/>";
+ d.innerHTML=dh;
+ document.body.appendChild(d);
+ return true;
+};
+
+function dhtmlxtreeErrorReport(a,b,c){
+ var str=a+" ["+b+"]";
+ if (a=='LoadXML')
+ {
+ str+="<br/>"+c[0].responseText+"</br>"+c[0].status;
+ }
+
+ window.onerror(str, "none", "none");
+}
+
+function dhtmlxtreeReport(node){
+ var that=node.parentNode;
+ that.lastChild.innerHTML="<textarea style='width:100%; height:300px;'></textarea>";
+ var rep=that.childNodes[1].innerHTML;
+ for (var a=0; a<_all_used_trees.length; a++){
+ var atree=_all_used_trees[a];
+ rep+="\n\n Tree "+a+"\n";
+ for (b in atree){
+ if (typeof(atree[b])=="function") continue;
+ rep+=b+"="+atree[b]+"\n";
+ }
+ rep+="---------------------\n";
+ if (atree.XMLLoader){
+ try{
+ var z=atree.XMLLoader.getXMLTopNode("tree")
+ if (document.all)
+ rep+=z.xml+"\n";
+ else{
+ var xmlSerializer = new XMLSerializer();
+ rep+=xmlSerializer.serializeToString(z)+"\n";
+ }
+ }
+ catch(e){
+ rep+="XML not recognised\n";
+ }
+ }
+
+ rep+="---------------------\n";
+ for (var i in atree._idpull){
+ var n=atree._idpull[i];
+ if (typeof(n)!='object') continue;
+ rep+="Node: "+n.id;
+ rep+=" Childs: "+n.childsCount;
+ for (var j=0; j<n.childsCount; j++)
+ rep+=" ch"+j+":"+n.childNodes[j].id;
+ rep+="\n";
+ }
+ }
+ that.lastChild.childNodes[0].value=rep;
+}
+
+dhtmlxError.catchError("ALL",dhtmlxtreeErrorReport);
+//(c)dhtmlx ltd. www.dhtmlx.com
diff --git a/funcweb/funcweb/static/javascript/ext/dhtmlxtree_json.js b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_json.js
new file mode 100644
index 0000000..4199512
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_json.js
@@ -0,0 +1,216 @@
+//v.1.6 build 80512
+
+/*
+Copyright DHTMLX LTD. http://www.dhtmlx.com
+You allowed to use this component or parts of it under GPL terms
+To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
+*/
+function jsonPointer(data,parent){
+ this.d=data;
+ this.dp=parent;
+}
+jsonPointer.prototype={
+ text:function(){ var afff=function(n){ var p=[]; for(var i=0; i<n.length; i++) p.push("{"+sfff(n[i])+"}"); return p.join(","); }; var sfff=function(n){ var p=[]; for (var a in n) if (typeof(n[a])=="object"){ if (a.length) p.push(a+":["+afff(n[a])+"]"); else p.push(a+":{"+sfff(n[a])+"}"); }else p.push(a+':"'+n[a]+'"'); return p.join(","); }; return "{"+sfff(this.d)+"}"; },
+ get:function(name){return this.d[name]; },
+ exists:function(){return !!this.d },
+ content:function(){return this.d.content; },
+ each:function(name,f,t){ var a=this.d[name]; var c=new jsonPointer(); if (a) for (var i=0; i<a.length; i++) { c.d=a[i]; f.apply(t,[c,i]); } },
+ get_all:function(){ return this.d; },
+ sub:function(name){ return new jsonPointer(this.d[name],this.d) },
+ sub_exists:function(name){ return !!this.d[name]; },
+ each_x:function(name,rule,f,t,i){ var a=this.d[name]; var c=new jsonPointer(0,this.d); if (a) for (i=i||0; i<a.length; i++) if (a[i][rule]) { c.d=a[i]; if(f.apply(t,[c,i])==-1) return; } },
+ up:function(name){ return new jsonPointer(this.d.parentNode,this.d); },
+ set:function(name,val){ this.d[name]=val; },
+ clone:function(name){ return new jsonPointer(this.d,this.dp); },
+ through:function(name,rule,v,f,t){ var a=this.d[name]; if (a.length) for (var i=0; i<a.length; i++) { if (a[i][rule]!=null && a[i][rule]!="" && (!v || a[i][rule]==v )) { var c=new jsonPointer(a[i],this.d); f.apply(t,[c,i]); } var w=this.d; this.d=a[i]; if (this.sub_exists(name)) this.through(name,rule,v,f,t); this.d=w; } }
+}
+
+/**
+* @desc: load tree from js array file|stream
+* @type: public
+* @param: file - link to JSArray file
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.loadJSArrayFile=function(file,afterCall){
+ if (!this.parsCount) this.callEvent("onXLS",[this,this._ld_id]); this._ld_id=null; this.xmlstate=1;
+ var that=this;
+
+ this.XMLLoader=new dtmlXMLLoaderObject(function(){
+ eval("var z="+arguments[4].xmlDoc.responseText);
+ that.loadJSArray(z);
+ },this,true,this.no_cashe);
+ if (afterCall) this.XMLLoader.waitCall=afterCall;
+ this.XMLLoader.loadXML(file);
+ };
+
+/**
+* @desc: load tree from csv file|stream
+* @type: public
+* @param: file - link to CSV file
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.loadCSV=function(file,afterCall){
+ if (!this.parsCount) this.callEvent("onXLS",[this,this._ld_id]); this._ld_id=null; this.xmlstate=1;
+ var that=this;
+ this.XMLLoader=new dtmlXMLLoaderObject(function(){
+ that.loadCSVString(arguments[4].xmlDoc.responseText);
+ },this,true,this.no_cashe);
+ if (afterCall) this.XMLLoader.waitCall=afterCall;
+ this.XMLLoader.loadXML(file);
+ };
+
+/**
+* @desc: load tree from js array object
+* @type: public
+* @param: ar - js array
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.loadJSArray=function(ar,afterCall){
+ //array id,parentid,text
+ var z=[];
+ for (var i=0; i<ar.length; i++){
+ if (!z[ar[i][1]]) z[ar[i][1]]=[];
+ z[ar[i][1]].push({id:ar[i][0],text:ar[i][2]});
+ }
+
+ var top={id: this.rootId};
+ var f=function(top,f){
+ if (z[top.id]){
+ top.item=z[top.id];
+ for (var j=0; j<top.item.length; j++)
+ f(top.item[j],f);
+ }
+ }
+ f(top,f);
+ this.loadJSONObject(top,afterCall);
+}
+
+
+/**
+* @desc: load tree from csv string
+* @type: public
+* @param: csv - csv string
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.loadCSVString=function(csv,afterCall){
+ //array id,parentid,text
+ var z=[];
+ var ar=csv.split("\n");
+ for (var i=0; i<ar.length; i++){
+ var t=ar[i].split(",");
+ if (!z[t[1]]) z[t[1]]=[];
+ z[t[1]].push({id:t[0],text:t[2]});
+ }
+
+ var top={id: this.rootId};
+ var f=function(top,f){
+ if (z[top.id]){
+ top.item=z[top.id];
+ for (var j=0; j<top.item.length; j++)
+ f(top.item[j],f);
+ }
+ }
+ f(top,f);
+ this.loadJSONObject(top,afterCall);
+}
+
+
+/**
+* @desc: load tree from json object
+* @type: public
+* @param: json - json object
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.loadJSONObject=function(json,afterCall){
+ if (!this.parsCount) this.callEvent("onXLS",[this,null]);this.xmlstate=1;
+ var p=new jsonPointer(json);
+ this._parse(p);
+ this._p=p;
+ if (afterCall) afterCall();
+ };
+
+
+/**
+* @desc: load tree from json file
+* @type: public
+* @param: file - link to JSON file
+* @param: afterCall - function which will be called after xml loading
+* @topic: 0
+*/
+ dhtmlXTreeObject.prototype.loadJSON=function(file,afterCall){
+ if (!this.parsCount) this.callEvent("onXLS",[this,this._ld_id]); this._ld_id=null; this.xmlstate=1;
+ var that=this;
+
+ this.XMLLoader=new dtmlXMLLoaderObject(function(){
+ eval("var t="+arguments[4].xmlDoc.responseText);
+ var p=new jsonPointer(t);
+ that._parse(p);
+ that._p=p;
+ },this,true,this.no_cashe);
+
+ if (afterCall) this.XMLLoader.waitCall=afterCall;
+ this.XMLLoader.loadXML(file);
+ };
+
+
+/**
+* @desc: return tree as json string
+* @type: public
+* @topic: 0
+*/
+dhtmlXTreeObject.prototype.serializeTreeToJSON=function(){
+ var out=["{id:'"+this.rootId+"', item:["];
+ var p=[];
+ for (var i=0; i<this.htmlNode.childsCount; i++)
+ p.push(this._serializeItemJSON(this.htmlNode.childNodes[i]));
+ out.push(p.join(","));
+ out.push("]}");
+ return out.join("");
+};
+dhtmlXTreeObject.prototype._serializeItemJSON=function(itemNode){
+ var out=[];
+ if (itemNode.unParsed)
+ return (itemNode.unParsed.text());
+
+ if (this._selected.length)
+ var lid=this._selected[0].id;
+ else lid="";
+ var text=itemNode.span.innerHTML;
+
+ if (this._xescapeEntities)
+ for (var i=0; i<this._serEnts.length; i++)
+ text=text.replace(this._serEnts[i][2],this._serEnts[i][1]);
+
+ if (!this._xfullXML)
+ out.push('{ id:"'+itemNode.id+'", '+(this._getOpenState(itemNode)==1?' open:"1", ':'')+(lid==itemNode.id?' select:"1",':'')+' text:"'+text+'"'+( ((this.XMLsource)&&(itemNode.XMLload==0))?", child:\"1\" ":""));
+ else
+ out.push('{ id:"'+itemNode.id+'", '+(this._getOpenState(itemNode)==1?' open:"1", ':'')+(lid==itemNode.id?' select:"1",':'')+' text:"'+text+'", im0:"'+itemNode.images[0]+'", im1:"'+itemNode.images[1]+'", im2:"'+itemNode.images[2]+'" '+(itemNode.acolor?(', aCol:"'+itemNode.acolor+'" '):'')+(itemNode.scolor?(', sCol:"'+itemNode.scolor+'" '):'')+(itemNode.checkstate==1?', checked:"1" ':(itemNode.checkstate==2?', checked:"-1"':''))+(itemNode.closeable?', closeable:"1" ':''));
+
+ if ((this._xuserData)&&(itemNode._userdatalist))
+ {
+ out.push(", userdata:[");
+ var names=itemNode._userdatalist.split(",");
+ var p=[];
+ for (var i=0; i<names.length; i++)
+ p.push("{ name:\""+names[i]+"\" , content:\""+itemNode.userData["t_"+names[i]]+"\" }");
+ out.push(p.join(",")); out.push("]");
+ }
+
+ if (itemNode.childsCount){
+ out.push(", item:[");
+ var p=[];
+ for (var i=0; i<itemNode.childsCount; i++)
+ p.push(this._serializeItemJSON(itemNode.childNodes[i]));
+ out.push(p.join(","));
+ out.push("]\n");
+ }
+
+ out.push("}\n")
+ return out.join("");
+}
+//(c)dhtmlx ltd. www.dhtmlx.com \ No newline at end of file
diff --git a/funcweb/funcweb/static/javascript/ext/dhtmlxtree_start.js b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_start.js
new file mode 100644
index 0000000..3c930d8
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/ext/dhtmlxtree_start.js
@@ -0,0 +1,101 @@
+//v.1.6 build 80512
+
+/*
+Copyright DHTMLX LTD. http://www.dhtmlx.com
+You allowed to use this component or parts of it under GPL terms
+To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
+*/
+function dhtmlXTreeFromHTML(obj){
+ if (typeof(obj)!="object")
+ obj=document.getElementById(obj);
+
+ var n=obj;
+ var id=n.id;
+ var cont="";
+
+ for (var j=0; j<obj.childNodes.length; j++)
+ if (obj.childNodes[j].nodeType=="1"){
+ if (obj.childNodes[j].tagName=="XMP"){
+ var cHead=obj.childNodes[j];
+ for (var m=0; m<cHead.childNodes.length; m++)
+ cont+=cHead.childNodes[m].data;
+
+ }
+ else if (obj.childNodes[j].tagName.toLowerCase()=="ul")
+ cont=dhx_li2trees(obj.childNodes[j],new Array(),0);
+ break;
+ }
+ obj.innerHTML="";
+
+
+ var t=new dhtmlXTreeObject(obj,"100%","100%",0);
+ var z_all=new Array();
+ for ( b in t )
+ z_all[b.toLowerCase()]=b;
+
+ var atr=obj.attributes;
+ for (var a=0; a<atr.length; a++)
+ if ((atr[a].name.indexOf("set")==0)||(atr[a].name.indexOf("enable")==0)){
+ var an=atr[a].name;
+ if (!t[an])
+ an=z_all[atr[a].name];
+ t[an].apply(t,atr[a].value.split(","));
+ }
+
+ if (typeof(cont)=="object"){
+ t.XMLloadingWarning=1;
+ for (var i=0; i<cont.length; i++){
+ var n=t.insertNewItem(cont[i][0],cont[i][3],cont[i][1]);
+ if (cont[i][2]) t._setCheck(n,cont[i][2]);
+ }
+ t.XMLloadingWarning=0;
+ t.lastLoadedXMLId=0;
+ t._redrawFrom(t);
+ }
+ else
+ t.loadXMLString("<tree id='0'>"+cont+"</tree>");
+ window[id]=t;
+ return t;
+}
+
+function dhx_init_trees(){
+ var z=document.getElementsByTagName("div");
+ for (var i=0; i<z.length; i++)
+ if (z[i].className=="dhtmlxTree")
+ dhtmlXTreeFromHTML(z[i])
+}
+
+function dhx_li2trees(tag,data,ind){
+ for (var i=0; i<tag.childNodes.length; i++){
+ var z=tag.childNodes[i];
+ if ((z.nodeType==1)&&(z.tagName.toLowerCase()=="li")){
+ var c=""; var ul=null;
+ var check=z.getAttribute("checked");
+ for (var j=0; j<z.childNodes.length; j++){
+ var zc=z.childNodes[j];
+ if (zc.nodeType==3) c+=zc.data;
+ else if (zc.tagName.toLowerCase()!="ul") c+=dhx_outer_html(zc);
+ else ul=zc;
+ }
+
+ data[data.length]=[ind,c,check,(z.id||(data.length+1))];
+ if (ul)
+ data=dhx_li2trees(ul,data,(z.id||data.length));
+ }
+ }
+ return data;
+}
+
+function dhx_outer_html(node){
+ if (node.outerHTML) return node.outerHTML;
+ var temp=document.createElement("DIV");
+ temp.appendChild(node.cloneNode(true));
+ temp=temp.innerHTML;
+ return temp;
+}
+
+if (window.addEventListener) window.addEventListener("load",dhx_init_trees,false);
+else if (window.attachEvent) window.attachEvent("onload",dhx_init_trees);
+//(c)dhtmlx ltd. www.dhtmlx.com
+
+
diff --git a/funcweb/funcweb/static/javascript/jquery.js b/funcweb/funcweb/static/javascript/jquery.js
deleted file mode 100644
index 3747929..0000000
--- a/funcweb/funcweb/static/javascript/jquery.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * jQuery 1.2.3 - New Wave Javascript
- *
- * Copyright (c) 2008 John Resig (jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $
- * $Rev: 4663 $
- */
-(function(){if(window.jQuery)var _jQuery=window.jQuery;var jQuery=window.jQuery=function(selector,context){return new jQuery.prototype.init(selector,context);};if(window.$)var _$=window.$;window.$=jQuery;var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;var isSimple=/^.[^:#\[\.]*$/;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}else if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem)if(elem.id!=match[3])return jQuery().find(selector);else{this[0]=elem;this.length=1;return this;}else
-selector=[];}}else
-return new jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return new jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(selector.constructor==Array&&selector||(selector.jquery||selector.length&&selector!=window&&!selector.nodeType&&selector[0]!=undefined&&selector[0].nodeType)&&jQuery.makeArray(selector)||[selector]);},jquery:"1.2.3",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;this.each(function(i){if(this==elem)ret=i;});return ret;},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value==undefined)return this.length&&jQuery[type||"attr"](this[0],name)||undefined;else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
-return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
-selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return!selector?this:this.pushStack(jQuery.merge(this.get(),selector.constructor==String?jQuery(selector).get():selector.length!=undefined&&(!selector.nodeName||jQuery.nodeName(selector,"form"))?selector:[selector]));},is:function(selector){return selector?jQuery.multiFilter(selector,this).length>0:false;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
-return(this[0].value||"").replace(/\r/g,"");}return undefined;}return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=value.constructor==Array?value:[value];jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
-this.value=value;});},html:function(value){return value==undefined?(this.length?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value==null){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data==undefined&&this.length)data=jQuery.data(this[0],key);return data==null&&parts[1]?this.data(parts[0]):data;}else
-return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script")){scripts=scripts.add(elem);}else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.prototype.init.prototype=jQuery.prototype;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
-jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==1){target=this;i=0;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){if(target===options[name])continue;if(deep&&options[name]&&typeof options[name]=="object"&&target[name]&&!options[name].nodeType)target[name]=jQuery.extend(target[name],options[name]);else if(options[name]!=undefined)target[name]=options[name];}return target;};var expando="jQuery"+(new Date()).getTime(),uuid=0,windowData={};var exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i;jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/function/i.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
-script.appendChild(document.createTextNode(data));head.appendChild(script);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!=undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){if(args){if(object.length==undefined){for(var name in object)if(callback.apply(object[name],args)===false)break;}else
-for(var i=0,length=object.length;i<length;i++)if(callback.apply(object[i],args)===false)break;}else{if(object.length==undefined){for(var name in object)if(callback.call(object[name],name,object[name])===false)break;}else
-for(var i=0,length=object.length,value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
-jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret;function color(elem){if(!jQuery.browser.safari)return false;var ret=document.defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(elem.style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=elem.style.outline;elem.style.outline="0 solid black";elem.style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&elem.style&&elem.style[name])ret=elem.style[name];else if(document.defaultView&&document.defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var getComputedStyle=document.defaultView.getComputedStyle(elem,null);if(getComputedStyle&&!color(elem))ret=getComputedStyle.getPropertyValue(name);else{var swap=[],stack=[];for(var a=elem;a&&color(a);a=a.parentNode)stack.unshift(a);for(var i=0;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(getComputedStyle&&getComputedStyle.getPropertyValue(name))||"";for(var i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var style=elem.style.left,runtimeStyle=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;elem.style.left=ret||0;ret=elem.style.pixelLeft+"px";elem.style.left=style;elem.runtimeStyle.left=runtimeStyle;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem=elem.toString();if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
-ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var fix=jQuery.isXMLDoc(elem)?{}:jQuery.props;if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(fix[name]){if(value!=undefined)elem[fix[name]]=value;return elem[fix[name]];}else if(jQuery.browser.msie&&name=="style")return jQuery.attr(elem.style,"cssText",value);else if(value==undefined&&jQuery.browser.msie&&jQuery.nodeName(elem,"form")&&(name=="action"||name=="method"))return elem.getAttributeNode(name).nodeValue;else if(elem.tagName){if(value!=undefined){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem.setAttribute(name,""+value);}if(jQuery.browser.msie&&/href|src/.test(name)&&!jQuery.isXMLDoc(elem))return elem.getAttribute(name,2);return elem.getAttribute(name);}else{if(name=="opacity"&&jQuery.browser.msie){if(value!=undefined){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseFloat(value).toString()=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100).toString():"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(value!=undefined)elem[name]=value;return elem[name];}},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(typeof array!="array")for(var i=0,length=array.length;i<length;i++)ret.push(array[i]);else
-ret=array.slice(0);return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]==elem)return i;return-1;},merge:function(first,second){if(jQuery.browser.msie){for(var i=0;second[i];i++)if(second[i].nodeType!=8)first.push(second[i]);}else
-for(var i=0;second[i];i++)first.push(second[i]);return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv&&callback(elems[i],i)||inv&&!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!==null&&value!=undefined){if(value.constructor!=Array)value=[value];ret=ret.concat(value);}}return ret;}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,innerHTML:"innerHTML",className:"className",value:"value",disabled:"disabled",checked:"checked",readonly:"readOnly",selected:"selected",maxlength:"maxLength",selectedIndex:"selectedIndex",defaultValue:"defaultValue",tagName:"tagName",nodeName:"nodeName"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false;var re=quickChild;var m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[];var cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&(!elem||n!=elem))r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval!=undefined)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=function(){return fn.apply(this,arguments);};handler.data=data;handler.guid=fn.guid;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){var val;if(typeof jQuery=="undefined"||jQuery.event.triggered)return val;val=jQuery.event.handle.apply(arguments.callee.elem,arguments);return val;});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
-for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data||[]);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event)data.unshift(this.fix({type:type,target:elem}));data[0].type=type;if(exclusive)data[0].exclusive=true;if(jQuery.isFunction(jQuery.data(elem,"handle")))val=jQuery.data(elem,"handle").apply(elem,data);if(!fn&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val;event=jQuery.event.fix(event||window.event||{});var parts=event.type.split(".");event.type=parts[0];var handlers=jQuery.data(this,"events")&&jQuery.data(this,"events")[event.type],args=Array.prototype.slice.call(arguments,1);args.unshift(event);for(var j in handlers){var handler=handlers[j];args[0].handler=handler;args[0].data=handler.data;if(!parts[1]&&!event.exclusive||handler.type==parts[1]){var ret=handler.apply(this,args);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}if(jQuery.browser.msie)event.target=event.preventDefault=event.stopPropagation=event.handler=event.data=null;return val;},fix:function(event){var originalEvent=event;event=jQuery.extend({},originalEvent);event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=originalEvent.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){return this.each(function(){jQuery.event.add(this,type,function(event){jQuery(this).unbind(event);return(fn||data).apply(this,arguments);},fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){if(this[0])return jQuery.event.trigger(type,data,this[0],false,fn);return undefined;},toggle:function(){var args=arguments;return this.click(function(event){this.lastToggle=0==this.lastToggle?1:0;event.preventDefault();return args[this.lastToggle].apply(this,arguments)||false;});},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
-jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.apply(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({load:function(url,params,callback){if(jQuery.isFunction(url))return this.bind("load",url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=(new Date).getTime();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){var jsonp,jsre=/=\?(&|$)/g,status,data;s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(s.type.toLowerCase()=="get"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&s.type.toLowerCase()=="get"){var ts=(new Date()).getTime();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&s.type.toLowerCase()=="get"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");if((!s.url.indexOf("http")||!s.url.indexOf("//"))&&s.dataType=="script"&&s.type.toLowerCase()=="get"){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xml=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();xml.open(s.type,s.url,s.async,s.username,s.password);try{if(s.data)xml.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xml.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xml.setRequestHeader("X-Requested-With","XMLHttpRequest");xml.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend)s.beforeSend(xml);if(s.global)jQuery.event.trigger("ajaxSend",[xml,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xml&&(xml.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xml)&&"error"||s.ifModified&&jQuery.httpNotModified(xml,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xml,s.dataType);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xml.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
-jQuery.handleError(s,xml,status);complete();if(s.async)xml=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xml){xml.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xml.send(s.data);}catch(e){jQuery.handleError(s,xml,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xml,s]);}function complete(){if(s.complete)s.complete(xml,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xml,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xml;},handleError:function(s,xml,status,e){if(s.error)s.error(xml,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xml,s,e]);},active:0,httpSuccess:function(r){try{return!r.status&&location.protocol=="file:"||(r.status>=200&&r.status<300)||r.status==304||r.status==1223||jQuery.browser.safari&&r.status==undefined;}catch(e){}return false;},httpNotModified:function(xml,url){try{var xmlRes=xml.getResponseHeader("Last-Modified");return xml.status==304||xmlRes==jQuery.lastModified[url]||jQuery.browser.safari&&xml.status==undefined;}catch(e){}return false;},httpData:function(r,type){var ct=r.getResponseHeader("content-type");var xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0;var data=xml?r.responseXML:r.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
-for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
-s.push(encodeURIComponent(j)+"="+encodeURIComponent(a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle(fn,fn2):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall);var hidden=jQuery(this).is(":hidden"),self=this;for(var p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return jQuery.isFunction(opt.complete)&&opt.complete.apply(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
-e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.apply(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(!elem)return undefined;type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",array?jQuery.makeArray(array):[]);return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].apply(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:{slow:600,fast:200}[opt.duration])||400;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.apply(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.apply(this.elem,[this.now,this]);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=(new Date()).getTime();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=(new Date()).getTime();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done&&jQuery.isFunction(this.options.complete))this.options.complete.apply(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.fx.step={scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}};jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),fixed=jQuery.css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&jQuery.css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(jQuery.css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&jQuery.css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||jQuery.css(offsetChild,"position")=="absolute"))||(mozilla&&jQuery.css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l)||0;top+=parseInt(t)||0;}return results;};})(); \ No newline at end of file
diff --git a/funcweb/funcweb/static/javascript/utils.js b/funcweb/funcweb/static/javascript/utils.js
new file mode 100644
index 0000000..810ba4d
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/utils.js
@@ -0,0 +1,238 @@
+function check_all(class_name){
+ var check_boxes = getElementsByTagAndClassName('input',class_name);
+ for (var check_element in check_boxes){
+ if (compare(check_boxes[check_element].checked,false)==0){
+ check_boxes[check_element].checked = true;
+ }
+ }
+}
+
+function uncheck_all(class_name){
+ var check_boxes = getElementsByTagAndClassName('input',class_name);
+ for (var check_element in check_boxes){
+ if (compare(check_boxes[check_element].checked,true)==0)
+ check_boxes[check_element].checked = false;
+ }
+
+}
+
+function checkController(class_name,check_element){
+ if (check_element.checked == true){
+ check_all(class_name);
+ }
+ else
+ uncheck_all(class_name);
+}
+
+/*
+ * Some ajaxian methods here (minion related stuff mostly !)
+ * These methods will replace the jquery and will let the Mochikit
+ * do all the stuff here !
+ */
+
+//------------------------------------------------------------------------------
+
+function list_minion_modules(minion_name){
+ /*
+ * Method that hanles all the stuff on index.html
+ * Therefore when you change something on index.html you should change
+ * that method also if it affects the related div ids below
+ */
+
+ //firstly do some hidings here
+ hideElement(getElement('resultcontent'));
+ hideElement(getElement('widgetcontent'));
+ hideElement(getElement('methotdscontent'));
+ hideElement(getElement('modulescontent'));
+ var base_url = '/funcweb/minion';
+ var data_pack = {'name':minion_name};
+ var div_to_replace = 'modulescontent';
+ //send the JSON request !
+ send_some_JSON(base_url,data_pack,div_to_replace);
+}
+
+function list_module_methods(minion_name,module_name){
+
+ //listing methods for specified module works for modules.html
+
+ hideElement(getElement('widgetcontent'));
+ hideElement(getElement('resultcontent'));
+ hideElement(getElement('methotdscontent'));
+ var base_url = '/funcweb/minion';
+ var data_pack = {
+ 'name':minion_name,
+ 'module':module_name
+ };
+ var div_to_replace = 'methotdscontent';
+ send_some_JSON(base_url,data_pack,div_to_replace);
+
+}
+
+function get_method_widget(minion_name,module_name,method_name){
+
+ // The method widget generator part works for methods.html
+
+ hideElement(getElement('resultcontent'));
+ hideElement(getElement('widgetcontent'));
+ var base_url = '/funcweb/method_display';
+ var data_pack = {
+ 'minion':minion_name,
+ 'module':module_name,
+ 'method':method_name
+ };
+ var div_to_replace = 'widgetcontent';
+ send_some_JSON(base_url,data_pack,div_to_replace);
+}
+
+
+function get_hosts_by_group(group_name){
+
+ //it is a part from group management api
+ //gets the hosts for specified group_name
+ hideElement(getElement('resultcontent'));
+ var base_url = '/funcweb/list_host_by_group';
+ var data_pack = {
+ 'group_name':group_name
+ };
+ var div_to_replace = 'miniongroupcontents';
+ send_some_JSON(base_url,data_pack,div_to_replace);
+}
+
+function execute_link_method(minion,module,method){
+
+ //execution part for methods that accept no arguments
+ hideElement(getElement('resultcontent'));
+ var base_url = '/funcweb/execute_link';
+ var data_pack = {
+ 'minion':minion,
+ 'module':module,
+ 'method':method
+ };
+ var div_to_replace = 'resultcontent';
+ send_some_JSON(base_url,data_pack,div_to_replace);
+}
+
+function send_some_JSON(base_url,data_pack,div_to_replace){
+ /*
+ * A common method that will responsible for sending
+ * simple Http request to server !
+ */
+ var d = doSimpleXMLHttpRequest(base_url, data_pack);
+ //var d = loadJSONDoc(base_url+queryString(data_pack));
+ d.addCallback(replace_div_success,div_to_replace);
+ //The errback will be a common method here !
+ d.addErrback(connection_error);
+
+}
+
+function replace_div_success(div_to_replace,result){
+ /*
+ * The common callback for ajax requests
+ */
+
+ var server_text = result.responseText;
+ var is_error = true;
+ var check_error = null;
+
+ //Because we got a response text it may not be a json object we should control it
+ //we report the errors with tubogears tg_flash variable so the control below
+ //simply tries to convert the response into JSON doc and pull the tg_flash variable's
+ //value. If it is null it seems tobe a normal response !
+ try{
+ check_error = evalJSON(server_text);
+ }
+ catch(e){
+ //There is no error in request
+ is_error = false;
+ }
+
+ if (is_error == true){
+ //js is so stupid damn :|
+ if (compare(check_error['fg_flash'],'null')!=0)
+ connection_error(check_error['tg_flash']);
+ else{
+ alert("It was marked as non error");
+ is_error = false;
+ }
+ }
+
+ if (is_error == false){
+ //Put the result into the target div
+ var replace_div = getElement(div_to_replace);
+ if (replace_div != null){
+ //first make it to appear here
+ showElement(replace_div);
+ replace_div.innerHTML = server_text;
+ }
+ }
+}
+
+function connection_error(error){
+ // The common errback method
+ var error_msg = "Async Request Error : You may try checking your connection and refresh your page! :" + repr(error);
+ alert("We got error in Async Request check the more detailed error report at the TOP of the page !");
+ var error_div = getElement("globalerror");
+ if (error_div != null){
+ error_div.innerHTML = error_msg;
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------
+function check_async_result(job_id){
+ //sends some request to get the current job ids status :)
+ hideElement(getElement('resultcontent'));
+ var base_url = '/funcweb/check_job_status';
+ var data_pack = {
+ 'job_id':job_id
+ };
+ var div_to_replace = 'resultcontent';
+ send_JSON_DOC_info(base_url,data_pack,div_to_replace);
+
+}
+
+
+function send_JSON_DOC_info(base_url,data_pack,div_to_replace){
+ /*
+ * That method is for getting the result that comes
+ * from minion side parsed in JSON format
+ * maybe used for other things also ...
+ */
+
+ d=loadJSONDoc(base_url,data_pack);
+ d.addCallback(load_parsed_result_tree,div_to_replace);
+ d.addErrback(connection_error);
+
+}
+
+function load_parsed_result_tree(div_to_replace,result){
+ /*
+ * The callback for showing the tree structure
+ */
+
+ //check for errors
+ if (compare(result['fg_flash'],null)!=0){
+ connection_error(result['tg_flash']);
+ return;
+ }
+
+ //firstly load the div that will include the tree
+ var replace_div = getElement(div_to_replace);
+ if (replace_div != null){
+ //first make it to appear here
+ showElement(replace_div);
+
+ //place here the tree div that will show up the tree structure
+ var html_code = '<div class="resultbigbox" id="resultbigbox"><div align="center" class="graytexts">Result</div><div class="resultbox" id="resultbox"><div id="treeboxbox_tree" style="width:200;height:200;border:0"></div></div></div>'
+ replace_div.innerHTML = html_code;
+ }
+
+ //now load the tree
+ tree=new dhtmlXTreeObject("treeboxbox_tree","100%","100%",0);
+ tree.setImagePath("/funcweb/static/images/imgs/");
+ tree.loadJSONObject(result['minion_result']);
+ alert("The tree should be loaded");
+
+
+}
+
+
diff --git a/funcweb/funcweb/templates/add_group.html b/funcweb/funcweb/templates/add_group.html
new file mode 100644
index 0000000..3386cbc
--- /dev/null
+++ b/funcweb/funcweb/templates/add_group.html
@@ -0,0 +1,20 @@
+<div class="minioncontent" id="addgroupcontent"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ >
+ <div class="addgroupbigbox" id="addgroupbigbox">
+ <div align="center" class="graytexts">Add Group</div>
+ <div class="graytexts" id="addgroup">
+ <div class="groupnametext" id="groupnametext">Name:</div>
+ <form id="form_addgroup" name="form_addgroup" method="post" onsubmit="return !glob_submit(this, 'groupscontent');" action="/funcweb/add_new_group">
+ <label>
+ <input name="group_name" type="text" class="addgroupbox" id="addgroupfield"/>
+ </label>
+ <label>
+ <input name="submit" type="submit" class="addnewgroupbtn" id="submit" value="ADD" />
+ </label>
+ </form>
+ </div>
+ </div>
+</div>
diff --git a/funcweb/funcweb/templates/async_table.html b/funcweb/funcweb/templates/async_table.html
index ca8849d..0614cc2 100644
--- a/funcweb/funcweb/templates/async_table.html
+++ b/funcweb/funcweb/templates/async_table.html
@@ -28,10 +28,10 @@
<td class="tableboxes">
<div class="newico" id="newico" py:if="job_pack[1] == 2"></div>
<div class="changedimg" id="changedimg" py:if="job_pack[1] == 1"></div>
- <span py:if="job_pack[0] == 0"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">RUNNING</a></span>
- <span py:if="job_pack[0] == 1"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">FINISHED</a></span>
- <span py:if="job_pack[0] == 3"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">PARTIAL</a></span>
- <span py:if="job_pack[0] == 4"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">ERROR</a></span>
+ <span py:if="job_pack[0] == 0"><a href="#resultcontent" onclick="check_async_result('${job_id}');">RUNNING</a></span>
+ <span py:if="job_pack[0] == 1"><a href="#resultcontent" onclick="check_async_result('${job_id}');">FINISHED</a></span>
+ <span py:if="job_pack[0] == 3"><a href="#resultcontent" onclick="check_async_result('${job_id}');">PARTIAL</a></span>
+ <span py:if="job_pack[0] == 4"><a href="#resultcontent" onclick="check_async_result('${job_id}');">ERROR</a></span>
</td>
</tr>
diff --git a/funcweb/funcweb/templates/glob_form.html b/funcweb/funcweb/templates/glob_form.html
new file mode 100644
index 0000000..6ca07e5
--- /dev/null
+++ b/funcweb/funcweb/templates/glob_form.html
@@ -0,0 +1,13 @@
+<div class="minionglob" id="minionglob"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/">
+
+ <form action="${submit_adress}" method="post" onsubmit="return !glob_submit(this,'not_sure');" class="tableform" name="minion_form">
+ <div class="graytexts2" id="minionglobtext">
+ <div align="center">Minion Glob</div>
+ </div>
+ <input name="submit" type="submit" class="minionbutton" id="button" value="submit" border="0"/>
+ <input name="glob" type="text" class="minionbox" id="textfield" />
+ </form>
+</div>
+
diff --git a/funcweb/funcweb/templates/group_minion.html b/funcweb/funcweb/templates/group_minion.html
new file mode 100644
index 0000000..598c0ed
--- /dev/null
+++ b/funcweb/funcweb/templates/group_minion.html
@@ -0,0 +1,16 @@
+<div class="graytexts" id="miniongroupsbigbox"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <div class="minion_glob_box" id="minion_glob_box">
+ <xi:include href="glob_form.html"/>
+ </div>
+ <div id="group_small">
+ <xi:include href="group_small.html"/>
+ </div>
+ <div id="minion_small">
+ <xi:include href="minion_small.html"/>
+ </div>
+
+</div>
diff --git a/funcweb/funcweb/templates/group_small.html b/funcweb/funcweb/templates/group_small.html
new file mode 100644
index 0000000..af7cbfe
--- /dev/null
+++ b/funcweb/funcweb/templates/group_small.html
@@ -0,0 +1,27 @@
+<div class="group" id="group"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/">
+ <div align="center">Group</div>
+ <form action="/funcweb/add_minions_togroup" method="post" onsubmit="return !glob_submit(this,'group_small');" name="group_remove">
+ <div class="groupbox" id="groupbox">
+ <span py:for="host in hosts">
+ <div class="minionstextbox" id="minionstextbox"><span class="minionsandgroupsbluetext">${host}</span>
+ <label>
+ <input type="checkbox" class="rmgroup" name="rmgroup" id="groupcheckbox" value="${host}"/>
+ </label>
+ </div>
+ </span>
+ </div>
+ <div class="selectallgroupboxes" id="selectallgroupboxes">
+ <input type="hidden" name="action_name" value="remove"/>
+ <input type="hidden" name="group_name" value="${group_name}"/>
+ <span class="graytexts2">Select all:</span>
+ <label>
+ <input type="checkbox" name="check_all_group" id="check_all_group" onclick="checkController('rmgroup',this);"/>
+ </label>
+ <label>
+ <input name="removegroups" type="submit" class="addnewgroupbtn" id="removegroups" value="Remove" />
+ </label>
+ </div>
+ </form>
+</div>
diff --git a/funcweb/funcweb/templates/groups_main.html b/funcweb/funcweb/templates/groups_main.html
new file mode 100644
index 0000000..4fdce0d
--- /dev/null
+++ b/funcweb/funcweb/templates/groups_main.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="master.html"/>
+ <head/>
+ <body>
+ <xi:include href="add_group.html" />
+ <div class="minioncontent" id="groupscontent">
+ <xi:include href="list_group.html" />
+ </div>
+
+ <div class="minioncontent" id="miniongroupcontents">
+ <!-- group_minion ends here -->
+ </div>
+ <a name="miniongroupcontents"/>
+
+ </body>
+</html>
diff --git a/funcweb/funcweb/templates/index.html b/funcweb/funcweb/templates/index.html
index 87c446e..f0604e1 100644
--- a/funcweb/funcweb/templates/index.html
+++ b/funcweb/funcweb/templates/index.html
@@ -6,24 +6,13 @@
<head/>
<body onLoad = "window.setTimeout('check_async_change()',10000);">
- <div class="minionglob" id="minionglob">
- <form action="/funcweb/minions" method="post" onsubmit="return !remoteFormRequest(this, 'minioncontent', {&quot;loading&quot;: null, &quot;confirm&quot;: null, &quot;after&quot;: null, &quot;on_complete&quot;: null, &quot;loaded&quot;: null, &quot;on_failure&quot;: null, &quot;on_success&quot;: null, &quot;before&quot;:&quot;myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide();&quot;});" class="tableform" name="minion_form">
-
- <div class="graytexts2" id="minionglobtext">
- <div align="center">Minion Glob</div>
- </div>
- <input name="submit" type="submit" class="minionbutton" id="button" value="submit" border="0"/>
- <input name="glob" type="text" class="minionbox" id="textfield" />
- </form>
- </div>
-
-
- <div class="emptyimagebox" id="emptyimagebox"></div>
- <div class="minioncontent" id="minioncontent">
+ <xi:include href="glob_form.html" />
+ <div class="emptyimagebox" id="emptyimagebox"></div>
+ <div class="minioncontent" id="minioncontent">
<div class="minionsbigbox" id="minionsbigbox" py:if="minions">
<div align="center" class="graytexts">Mininons</div>
<div id="minionstexts" py:for="minion in minions">
- <a onclick="myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide().load('/funcweb/minion/${minion}').show('slow');" href="#modulescontent" class="minionstextblue">${minion}</a>
+ <a onclick="list_minion_modules('${minion}');" href="#modulescontent" class="minionstextblue">${minion}</a>
</div>
</div>
<div class="errorbox" id="errorbox" py:if="not minions">There is no minion to display with that glob, try something different</div>
diff --git a/funcweb/funcweb/templates/list_group.html b/funcweb/funcweb/templates/list_group.html
new file mode 100644
index 0000000..cea4732
--- /dev/null
+++ b/funcweb/funcweb/templates/list_group.html
@@ -0,0 +1,16 @@
+<div class="groupsbigbox" id="groupsbigbox"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/">
+
+ <div align="center" class="graytexts">Groups</div>
+ <span py:for="group_name in groups">
+ <div class="minionstextblue" id="groupstexts"><a href="#miniongroupcontents" onclick="get_hosts_by_group('${group_name}');">${group_name}</a></div>
+ <form action="/funcweb/remove_group" method="post" onsubmit="return !glob_submit(this,'groupscontent');" name="remove_form">
+
+ <input type="hidden" name="group_name" value="${group_name}"/>
+ <span>
+ <input name="removebtn2" type="submit" class="removebtn" id="removebtn" value=""/>
+ </span>
+ </form>
+ </span>
+</div>
diff --git a/funcweb/funcweb/templates/master.html b/funcweb/funcweb/templates/master.html
index 0b5bcae..21df0f5 100644
--- a/funcweb/funcweb/templates/master.html
+++ b/funcweb/funcweb/templates/master.html
@@ -6,26 +6,37 @@
<head py:match="head" py:attrs="select('@*')">
<meta content="text/html; charset=UTF-8" http-equiv="content-type"
py:replace="''" />
- <title py:content="'Your Title Goes Here'"></title>
+ <title py:content="'Funcweb'"></title>
- <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/jquery.js')}" />
<link py:for="js in tg_js_head" py:strip="">${ET(js.display())}</link>
<link py:for="css in tg_css" py:strip="">${ET(css.display())}</link>
<script type="text/javascript" src="${tg.url('/funcweb/static/javascript/ajax.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/utils.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/dhtmlxcommon.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/dhtmlxtree.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/ext/dhtmlxtree_dragin.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/ext/dhtmlxtree_ed.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/ext/dhtmlxtree_er.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/ext/dhtmlxtree_json.js')}" />
+ <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/ext/dhtmlxtree_start.js')}" />
- <style type="text/css" media="screen">
+ <style type="text/css" media="screen">
@import url("/funcweb/static/css/style.css");
</style>
+ <style type="text/css" media="screen">
+ @import url("/funcweb/static/css/groupscss.css");
+ </style>
+ <style type="text/css" media="screen">
+ @import url("/funcweb/static/css/dhtmlxtree.css");
+ </style>
+
+
<link media="screen" href="/funcweb/static/css/expanding_form.css" type="text/css" rel="stylesheet"/>
<script src="${tg.url('/funcweb/static/javascript/expanding_form.js')}" type="text/javascript"/>
<script src="${tg.url('/funcweb/static/javascript/async_tools.js')}" type="text/javascript"/>
- <script type="text/javascript">
- jQuery._$ = MochiKit.DOM.getElement;
- var myj = jQuery.noConflict();
- </script>
</head>
<body py:match="body" py:attrs="select('@*')">
@@ -35,7 +46,14 @@
<div class="underheader" id="underheader"></div>
<div id="menudiv">
<div class="navgation" id="navigaton">
- <span class="lines">|</span><a href="/funcweb/" class="navlinks">Home</a><span class="lines">|</span><a href="/funcweb/display_async_results" class="navlinks">Async Results</a><span class="lines">|</span>
+ <span class="lines">|</span>
+ <a href="/funcweb/" class="navlinks">Home</a>
+ <span class="lines">|</span>
+ <a href="/funcweb/display_async_results" class="navlinks">Async Results</a>
+ <span class="lines">|</span>
+ <a href="/funcweb/groups_main" class="navlinks">Group Management</a>
+ <span class="lines">|</span>
+
</div>
</div>
diff --git a/funcweb/funcweb/templates/methods.html b/funcweb/funcweb/templates/methods.html
index 9f06cbb..8c8465c 100644
--- a/funcweb/funcweb/templates/methods.html
+++ b/funcweb/funcweb/templates/methods.html
@@ -8,7 +8,7 @@
<span py:for="minion, methods in modules.items()">
<div align="center" class="graytexts">${minion}.${module}</div>
<div class="minionstextblue" id="methodstextbox" py:for="method in methods">
- <a href="#widgetcontent" onclick="myj('#resultcontent').hide();myj('#widgetcontent').hide().load('/funcweb/method_display/${minion}/${module}/${method}').show('slow')" class="minionstextblue">${method}</a>
+ <a href="#widgetcontent" onclick="get_method_widget('${minion}','${module}','${method}');" class="minionstextblue">${method}</a>
</div>
</span>
</div>
diff --git a/funcweb/funcweb/templates/minion_small.html b/funcweb/funcweb/templates/minion_small.html
new file mode 100644
index 0000000..adf841c
--- /dev/null
+++ b/funcweb/funcweb/templates/minion_small.html
@@ -0,0 +1,28 @@
+<div class="minions2" id="minions2"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/">
+
+ <div align="center">Minions</div>
+ <form action="/funcweb/add_minions_togroup" method="post" onsubmit="return !glob_submit(this,'group_small');" name="minion_merge">
+ <div class="minions2box" id="minions2box">
+ <span py:for="minion in all_minions">
+ <div class="minionstextbox" id="minionstextbox"><span class="minionsandgroupsbluetext">${minion}</span>
+ <label>
+ <input type="checkbox" class = "checkminion" name="checkminion" id="checkminion" value="${minion}"/>
+ </label>
+ </div>
+ </span>
+ </div>
+ <div class="graytexts2" id="selectallbox"> Select all:
+ <label>
+ <input type="checkbox" name="check_all_minion" id="check_all_minion" onclick="checkController('checkminion',this);"/>
+ </label>
+
+ <input type="hidden" name="group_name" value="${group_name}"/>
+ <input type="hidden" name="action_name" value="add"/>
+ <label>
+ <input name="addbtn" type="submit" class="addnewgroupbtn" id="addbtn" value="Add" />
+ </label>
+ </div>
+ </form>
+</div>
diff --git a/funcweb/funcweb/templates/minions.html b/funcweb/funcweb/templates/minions.html
index 08863e8..7659bcd 100644
--- a/funcweb/funcweb/templates/minions.html
+++ b/funcweb/funcweb/templates/minions.html
@@ -7,7 +7,7 @@
<div class="minionsbigbox" id="minionsbigbox" py:if="minions">
<div align="center" class="graytexts">Minions</div>
<div id="minionstexts" py:for="minion in minions">
- <a onclick="myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide().load('/funcweb/minion/${minion}').show('slow');" href="#modulescontent" class="minionstextblue">${minion}</a>
+ <a onclick="list_minion_modules('${minion}');" href="#modulescontent" class="minionstextblue">${minion}</a>
</div>
</div>
<div class="errorbox" id="errorbox" py:if="not minions">There is no minion to display with that glob, try something different</div>
diff --git a/funcweb/funcweb/templates/modules.html b/funcweb/funcweb/templates/modules.html
index 2d8107b..c610c11 100644
--- a/funcweb/funcweb/templates/modules.html
+++ b/funcweb/funcweb/templates/modules.html
@@ -8,7 +8,7 @@
<div align="center" class="graytexts">${minion}</div>
<div class="modulestexts" id="modulestexts" py:for="module in modules">
- <a href="#methotdscontent" class="minionstextblue" onclick="myj('#widgetcontent').hide();myj('#resultcontent').hide();myj('#methotdscontent').hide().load('/funcweb/minion/${minion}/${module}').show('slow')">${module}</a>
+ <a href="#methotdscontent" class="minionstextblue" onclick="list_module_methods('${minion}','${module}');">${module}</a>
</div>
</span>
</div>
diff --git a/funcweb/funcweb/templates/widgets.html b/funcweb/funcweb/templates/widgets.html
index d898134..f85dfd7 100644
--- a/funcweb/funcweb/templates/widgets.html
+++ b/funcweb/funcweb/templates/widgets.html
@@ -13,7 +13,7 @@
${ET(minion_form.display(displays_on='genshi'))}
</span>
<span py:if="not minion_form">
- <a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/execute_link/${minion}/${module}/${method}/').show('slow');">Run Method</a>
+ <a href="#resultcontent" onclick="execute_link_method('${minion}','${module}','${method}');">Run Method</a>
</span>
</div>
<div class="errorbox" id="errorbox">
diff --git a/funcweb/funcweb/tests/test_result_handler.py b/funcweb/funcweb/tests/test_result_handler.py
new file mode 100644
index 0000000..95dcf73
--- /dev/null
+++ b/funcweb/funcweb/tests/test_result_handler.py
@@ -0,0 +1,429 @@
+#all the test cases which are 16 and handle 4 level
+#list hash indentation are tested manually because
+#couldnt find a way to automate that process :)
+#zeros stands for dict type 1 id for lists
+
+test_0000 = {
+ 'minion1':{
+ 'result1':{
+ 'result11':{
+ 'result111':{
+ 'result1111':1111
+ }
+ }
+ },
+ 'result12':{
+ 'result12':{
+ 'result122':{
+ 'result1222':1222
+ }
+ }
+ }
+ },
+ 'minion2':{
+ 'result2':{
+ 'result22':{
+ 'result222':{
+ 'result2222':2222
+ }
+ }
+ }
+ ,
+ 'result2s':{
+ 'result2s':{
+ 'result12s':{
+ 'result122s':1225
+ }
+ }
+ }
+ }
+ }
+
+test_0001 = {
+ 'minion1':{
+ 'result1':{
+ 'result11':{
+ 'result111':[1111,1111,1111]
+ }
+ },
+
+ 'result12':{
+ 'result12':{
+ 'result122':[1222,1222,1222]
+ }
+ }
+ },
+ 'minion2':{
+ 'result2':{
+ 'result22':{
+ 'result222':[2222,2222,2222]
+ }
+ },
+ 'result2s':{
+ 'result2s':{
+ 'result12s':[2225,2225,2225]
+ }
+ }
+ }
+ }
+
+test_0010 = {
+ 'minion1':{
+ 'result1':{
+ 'result11':[{'res111':111},{'res111':111}]
+ },
+ 'result12':{
+ 'result122':[{'res1222':1222},{'res1222':1222}]
+ }
+ },
+ 'minion2':{
+ 'result2':{
+ 'result22':[{'res222':222},{'res222':222}]
+ },
+ 'result25':{
+ 'result225':[{'res2225':2225},{'res2225':2225}]
+ }
+ }
+ }
+
+test_0011 = {
+ 'minion1':{
+ 'result1':{
+ 'result11':[[1111,1111],[1111,1111]]
+ },
+ 'result12':{
+ 'result122':[[1222,1222],[1222,1222]]
+ }
+ },
+ 'minion2':{
+ 'result2':{
+ 'result22':[[2222,2222],[2222,2222]]
+ },
+ 'result25':{
+ 'result225':[[2225,2225],[2225,2225]]
+ }
+ }
+ }
+
+test_0100 = {
+ 'minion1':{
+ 'result1':[
+ {'dict11':{'dict111':1111},'dict16':{'dict111':1111}},
+ {'dict12':{'dict122':1222},'dict18':{'dict122':1222}}
+ ],
+ 'result13':[
+ {'dict13':{'dict133':1333},'dict15':{'dict133':1333}},
+ {'dict14':{'dict144':1444},'dict16':{'dict144':1444}}
+ ]
+ },
+ 'minion2':{
+ 'result2':[
+ {'dict22':{'dict222':2222},'dict24':{'dict244':2444}},
+ {'dict23':{'dict233':2333},'dict25':{'dict255':2555}}
+ ],
+ 'result21':[
+ {'dict21':{'dict211':2111},'dict23':{'dict233':2333}},
+ {'dict24':{'dict244':2444},'dict27':{'dict244':2444}}
+ ]
+ }
+ }
+
+test_0101 = {
+ 'minion1':{
+ 'result1':[
+ {'dict11':[1111,1111],'dict16':[1666,1666]},
+ {'dict12':[1222,1222],'dict18':[1888,1888]}
+ ],
+ 'result13':[
+ {'dict13':[1333,1333],'dict15':[1555,1555]},
+ {'dict14':[1444,1444],'dict16':[1666,1666]}
+ ]
+ },
+ 'minion2':{
+ 'result2':[
+ {'dict22':[2222,2222],'dict24':[2444,2444]},
+ {'dict23':[2333,2333],'dict25':[2555,2555]}
+ ],
+ 'result21':[
+ {'dict21':[2111,2111],'dict23':[2333,2333]},
+ {'dict24':[2444,2444],'dict27':[2777,2777]}
+ ]
+ }
+ }
+
+test_0110 = {
+ 'minion1':{
+ 'result1':[
+ [{'dict11':[1111,1111]},{'dict16':[1666,1666]}],
+ [{'dict12':[1222,1222]},{'dict18':[1888,1888]}]
+ ],
+ 'result13':[
+ [{'dict13':[1333,1333]},{'dict15':[1555,1555]}],
+ [{'dict14':[1444,1444]},{'dict16':[1666,1666]}]
+ ]
+ },
+ 'minion2':{
+ 'result2':[
+ [{'dict22':[2222,2222]},{'dict24':[2444,2444]}],
+ [{'dict23':[2333,2333]},{'dict25':[2555,2555]}]
+ ],
+ 'result21':[
+ [{'dict21':[2111,2111]},{'dict23':[2333,2333]}],
+ [{'dict24':[2444,2444]},{'dict27':[2777,2777]}]
+ ]
+ }
+ }
+
+test_0111 = {
+ 'minion1':{
+ 'result1':[
+ [[1111,1111],[1666,1666]],
+ [[1222,1222],[1888,1888]]
+ ],
+ 'result13':[
+ [[1333,1333],[1555,1555]],
+ [[1444,1444],[1666,1666]]
+ ]
+ },
+ 'minion2':{
+ 'result2':[
+ [[2222,2222],[2444,2444]],
+ [[2333,2333],[2555,2555]]
+ ],
+ 'result21':[
+ [[2111,2111],[2333,2333]],
+ [[2444,2444],[2777,2777]]
+ ]
+ }
+ }
+
+test_1000 = {
+ 'minion1':{
+ 'res1': [
+ {'result11':{'result111':{'result1111':1111}}},
+ {'result13':{'result133':{'result1333':1333}}}
+ ],
+ 'res11':[
+ {'result15':{'result155':{'result1555':1555}}},
+ {'result17':{'result177':{'result1777':1777}}}
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ {'result21':{'result211':{'result2111':2111}}},
+ {'result23':{'result233':{'result2333':2333}}}
+ ],
+ 'res22':[
+ {'result25':{'result255':{'result2555':2555}}},
+ {'result27':{'result277':{'result2777':2777}}}
+ ],
+ }
+ }
+
+test_1001 = {
+ 'minion1':{
+ 'res1': [
+ {'result11':{'result111':[1111,1111]}},
+ {'result13':{'result133':[1333,1333]}}
+ ],
+ 'res11':[
+ {'result15':{'result155':[1555,1555]}},
+ {'result17':{'result177':[1777,1777]}}
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ {'result21':{'result211':[2111,2111]}},
+ {'result23':{'result233':[2333,2333]}}
+ ],
+ 'res22':[
+ {'result25':{'result255':[2555,2555]}},
+ {'result27':{'result277':[2777,2777]}}
+ ],
+ }
+ }
+
+test_1010 = {
+ 'minion1':{
+ 'res1': [
+ {'result11':[{'result111':[1111,1111]}]},
+ {'result13':[{'result133':[1333,1333]}]}
+ ],
+ 'res11':[
+ {'result15':[{'result155':[1555,1555]}]},
+ {'result17':[{'result177':[1777,1777]}]}
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ {'result21':[{'result211':[2111,2111]}]},
+ {'result23':[{'result233':[2333,2333]}]}
+ ],
+ 'res22':[
+ {'result25':[{'result255':[2555,2555]}]},
+ {'result27':[{'result277':[2777,2777]}]}
+ ],
+ }
+ }
+
+
+test_1011 = {
+ 'minion1':{
+ 'res1': [
+ {'result11':[[1111,1111],[1111,1111]]},
+ {'result13':[[1333,1333],[1333,1333]]}
+ ],
+ 'res11':[
+ {'result15':[[1555,1555],[1555,1555]]},
+ {'result17':[{'result177':[1777,1777]}]}
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ {'result21':[[2111,2111],[2111,2111]]},
+ {'result23':[[2333,2333],[2333,2333]]}
+ ],
+ 'res22':[
+ {'result25':[[2555,2555],[2555]]},
+ {'result27':[[2777,2777],[2555]]}
+ ],
+ }
+ }
+
+test_1100 = {
+ 'minion1':{
+ 'res1': [
+ [{'result11':{'result111':{'result1111':1111}}}],
+ [{'result13':{'result133':{'result1333':1333}}}]
+ ],
+ 'res11':[
+ [{'result15':{'result155':{'result1555':1555}}}],
+ [{'result17':{'result177':{'result1777':1777}}}]
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ [{'result21':{'result211':{'result2111':2111}}}],
+ [{'result23':{'result233':{'result2333':2333}}}]
+ ],
+ 'res22':[
+ [{'result25':{'result255':{'result2555':2555}}}],
+ [{'result27':{'result277':{'result2777':2777}}}]
+ ],
+ }
+ }
+
+test_1101 = {
+ 'minion1':{
+ 'res1': [
+ [{'result11':{'result111':[1111,1111,1111]}}],
+ [{'result13':{'result133':[1333,1333,1333]}}]
+ ],
+ 'res11':[
+ [{'result15':{'result155':[1555,1555,1555]}}],
+ [{'result17':{'result177':[1777,1777,1777]}}]
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ [{'result21':{'result211':[2111,2111,2111]}}],
+ [{'result23':{'result233':[2333,2333,2333]}}]
+ ],
+ 'res22':[
+ [{'result25':{'result255':[2555,2555,2555]}}],
+ [{'result27':{'result277':[2777,2777,2777]}}]
+ ],
+ }
+ }
+
+test_1110 = {
+ 'minion1':{
+ 'res1': [
+ [[{'result111':{'result1111':1111}}]],
+ [[{'result133':{'result1333':1333}}]]
+ ],
+ 'res11':[
+ [[{'result155':{'result1555':1555}}]],
+ [[{'result177':{'result1777':1777}}]]
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ [[{'result211':{'result2111':2111}}]],
+ [[{'result233':{'result2333':2333}}]]
+ ],
+ 'res22':[
+ [[{'result255':{'result2555':2555}}]],
+ [[{'result277':{'result2777':2777}}]]
+ ],
+ }
+ }
+
+
+test_1111 = {
+ 'minion1':{
+ 'res1': [
+ [[[1111,1111,1111],[1111,1111,1111]]],
+ [[[1222,1222,1222],[1222,1222,1222]]]
+ ],
+ 'res11':[
+ [[[1555,1555,1555],[1555,1555,1555]]],
+ [[[1777,1777,1777],[1777,1777,1777]]]
+ ],
+
+ },
+ 'minion2':{
+ 'res2':[
+ [[[2111,2111,2111],[2111,2111,2111]]],
+ [[[2333,2333,2333],[2333,2333,2333]]]
+ ],
+ 'res22':[
+ [[[2555,2555,2555],[2555,2555,2555]]],
+ [[[2777,2777,277],[2777,2777,2777]]]
+ ],
+ }
+ }
+
+test_cases = [
+ test_0000,
+ test_0001,
+ test_0010,
+ test_0011,
+ test_0100,
+ test_0101,
+ test_0110,
+ test_0111,
+ test_1000,
+ test_1001,
+ test_1010,
+ test_1011,
+ test_1100,
+ test_1101,
+ test_1101,
+ test_1110,
+ test_1111
+ ]
+
+from funcweb.result_handler import produce_res_rec
+
+def test_result_handler():
+ """
+ Run handler cases
+ """
+
+ for test_case in test_cases:
+ result = produce_res_rec(test_case)
+ #not a perfect one but it is just a poc
+ #if sth is wrong can be seen here
+ #if someone wants to add more casess it is
+ #just enough to add them to the list
+ #print result
+ assert type(result) == list
+
diff --git a/funcweb/funcweb/widget_automation.py b/funcweb/funcweb/widget_automation.py
index fa83fcf..9769586 100644
--- a/funcweb/funcweb/widget_automation.py
+++ b/funcweb/funcweb/widget_automation.py
@@ -28,6 +28,8 @@ class WidgetListFactory(object):
'hash':{
'type':"RepeatingFieldSet"},
'list':{
+ 'type':"RepeatingFieldSet"},
+ 'list*':{
'type':"RepeatingFieldSet"}
}
#will contain the input widget created in that class
@@ -50,7 +52,8 @@ class WidgetListFactory(object):
self.method = method
def __add_general_widget(self):
-
+ # a mirror var to show that these are same things
+ mirror_case = {'list*':'list'}
#key is the argument_name and the argument are options
for key,argument in self.__argument_dict.iteritems():
#get the type of the argument
@@ -69,7 +72,10 @@ class WidgetListFactory(object):
if act_special:
#calling for example __add_specialized_string(..)
- getattr(self,"_%s__add_specialized_%s"%(self.__class__.__name__,current_type))(argument,key)
+ if current_type == "list*":
+ getattr(self,"_%s__add_specialized_%s"%(self.__class__.__name__,mirror_case[current_type]))(argument,key)
+ else:
+ getattr(self,"_%s__add_specialized_%s"%(self.__class__.__name__,current_type))(argument,key)
else:
temp_object = getattr(widgets,self.__convert_table[current_type]['default_value'])()
#add common options to it
@@ -261,7 +267,7 @@ class RemoteFormAutomation(CoreWD):
validator = validator_schema,
name = "minion_form",
update = "resultbox",
- before='myj(\'#resultcontent\').hide().show(\'slow\');addDomAjaxREsult();getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../funcweb/static/images/loading.gif\',width:\'100\',height:\'100\'}));',
+ before='hideElement(getElement(\'resultcontent\'));showElement(getElement(\'resultcontent\'));addDomAjaxREsult();getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../funcweb/static/images/loading.gif\',width:\'100\',height:\'100\'}));',
on_complete='getElement(\'loading\' ).innerHTML=\'Done!\';',
submit_text = "Send Command to Glob"
)
diff --git a/funcweb/funcweb/widget_validation.py b/funcweb/funcweb/widget_validation.py
index 9b67e7f..b04572a 100644
--- a/funcweb/funcweb/widget_validation.py
+++ b/funcweb/funcweb/widget_validation.py
@@ -23,11 +23,16 @@ class WidgetSchemaFactory(object):
and according to their types it sends the process to more specialized
validator adders
"""
-
+ # a mirror var to show that these are same things
+ mirror_case = {'list*':'list'}
for argument_name,argument_values in self.method_argument_dict.iteritems():
#some lazy stuff :)
#for ex : _add_int_validator(some_arg)
- getattr(self,"_add_%s_validator"%(argument_values['type']))(argument_name)
+ current_type = argument_values['type']
+ if current_type == "list*":
+ getattr(self,"_add_%s_validator"%(mirror_case[current_type]))(argument_name)
+ else:
+ getattr(self,"_add_%s_validator"%(current_type))(argument_name)
def _add_boolean_validator(self,argument_name):
bool_data_set = {}
diff --git a/funcweb/setup.py b/funcweb/setup.py
index e4e6cf7..fc12ca2 100644
--- a/funcweb/setup.py
+++ b/funcweb/setup.py
@@ -23,6 +23,8 @@ initpath = "/etc/init.d"
#the log path
logpath = "/var/log/funcweb"
rotpath = "/etc/logrotate.d"
+#the pam path
+pampath = "/etc/pam.d/"
#the setup part
setup(
@@ -93,6 +95,7 @@ setup(
(self_etcpath,['etc/prod.cfg']),
(initpath,['init-scripts/funcwebd']),
(logpath,[]),
- (rotpath,['etc/funcweb_rotate'])
+ (rotpath,['etc/funcweb_rotate']),
+ (pampath,['etc/pam.d/funcweb'])
],
)
diff --git a/test/unittest/test_groups.py b/test/unittest/test_groups.py
index 35c5a8f..9e1702c 100644
--- a/test/unittest/test_groups.py
+++ b/test/unittest/test_groups.py
@@ -98,8 +98,7 @@ class TestGroupsBase(object):
self.test_dict["home_group"].extend(["bloop","woop","zoo"])
result = self.minions.group_class.get_groups()
assert self.test_dict == result
-
- #add one for save
+ #add one for save
self.minions.group_class.add_host_list("home_group",["hey.com"],save = True)
result = self.minions.group_class.get_groups()
assert result == self.util_save_change()