diff options
author | Adrian Likins <alikins@redhat.com> | 2008-08-20 13:36:47 -0400 |
---|---|---|
committer | Adrian Likins <alikins@redhat.com> | 2008-08-20 13:36:47 -0400 |
commit | 82ed2583f2f9b2fe5ca89824340e12e8dbdef8ef (patch) | |
tree | 21b503dcafc7871bae5f1ca69c3d28d60086ee14 | |
parent | 4bd91c631f1d81daa416889b0521f95841a1a83a (diff) | |
parent | a07ef03e52427fa26f8990031705a86fdd7c9291 (diff) | |
download | func-82ed2583f2f9b2fe5ca89824340e12e8dbdef8ef.tar.gz func-82ed2583f2f9b2fe5ca89824340e12e8dbdef8ef.tar.xz func-82ed2583f2f9b2fe5ca89824340e12e8dbdef8ef.zip |
Merge branch 'master' of ssh://alikins@git.fedoraproject.org/git/hosted/func
116 files changed, 7775 insertions, 177 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 cc463cf..b41dd9b 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): @@ -42,3 +42,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/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/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 Binary files differnew file mode 100644 index 0000000..32d0e2d --- /dev/null +++ b/funcweb/funcweb/static/images/button_overadd.jpg diff --git a/funcweb/funcweb/static/images/buttonadd.jpg b/funcweb/funcweb/static/images/buttonadd.jpg Binary files differnew file mode 100644 index 0000000..5942919 --- /dev/null +++ b/funcweb/funcweb/static/images/buttonadd.jpg diff --git a/funcweb/funcweb/static/images/groupremovebtn.jpg b/funcweb/funcweb/static/images/groupremovebtn.jpg Binary files differnew file mode 100644 index 0000000..03adf3f --- /dev/null +++ b/funcweb/funcweb/static/images/groupremovebtn.jpg diff --git a/funcweb/funcweb/static/images/groupremovebtnhover.jpg b/funcweb/funcweb/static/images/groupremovebtnhover.jpg Binary files differnew file mode 100644 index 0000000..4c57451 --- /dev/null +++ b/funcweb/funcweb/static/images/groupremovebtnhover.jpg diff --git a/funcweb/funcweb/static/images/imgs/blank.gif b/funcweb/funcweb/static/images/imgs/blank.gif Binary files differnew file mode 100644 index 0000000..d7ae406 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/blank.gif diff --git a/funcweb/funcweb/static/images/imgs/but_cut.gif b/funcweb/funcweb/static/images/imgs/but_cut.gif Binary files differnew file mode 100644 index 0000000..942bd18 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/but_cut.gif diff --git a/funcweb/funcweb/static/images/imgs/folderClosed.gif b/funcweb/funcweb/static/images/imgs/folderClosed.gif Binary files differnew file mode 100644 index 0000000..1ebe3c9 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/folderClosed.gif diff --git a/funcweb/funcweb/static/images/imgs/folderOpen.gif b/funcweb/funcweb/static/images/imgs/folderOpen.gif Binary files differnew file mode 100644 index 0000000..c193e86 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/folderOpen.gif diff --git a/funcweb/funcweb/static/images/imgs/iconCheckAll.gif b/funcweb/funcweb/static/images/imgs/iconCheckAll.gif Binary files differnew file mode 100644 index 0000000..d908992 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/iconCheckAll.gif diff --git a/funcweb/funcweb/static/images/imgs/iconCheckDis.gif b/funcweb/funcweb/static/images/imgs/iconCheckDis.gif Binary files differnew file mode 100644 index 0000000..6f0b1c7 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/iconCheckDis.gif diff --git a/funcweb/funcweb/static/images/imgs/iconCheckGray.gif b/funcweb/funcweb/static/images/imgs/iconCheckGray.gif Binary files differnew file mode 100644 index 0000000..cb54c0a --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/iconCheckGray.gif diff --git a/funcweb/funcweb/static/images/imgs/iconUncheckAll.gif b/funcweb/funcweb/static/images/imgs/iconUncheckAll.gif Binary files differnew file mode 100644 index 0000000..5e54ec5 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/iconUncheckAll.gif diff --git a/funcweb/funcweb/static/images/imgs/iconUncheckDis.gif b/funcweb/funcweb/static/images/imgs/iconUncheckDis.gif Binary files differnew file mode 100644 index 0000000..eec88a7 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/iconUncheckDis.gif diff --git a/funcweb/funcweb/static/images/imgs/leaf.gif b/funcweb/funcweb/static/images/imgs/leaf.gif Binary files differnew file mode 100644 index 0000000..1cf40f1 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/leaf.gif diff --git a/funcweb/funcweb/static/images/imgs/line.gif b/funcweb/funcweb/static/images/imgs/line.gif Binary files differnew file mode 100644 index 0000000..60f2ccb --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line.gif diff --git a/funcweb/funcweb/static/images/imgs/line1.gif b/funcweb/funcweb/static/images/imgs/line1.gif Binary files differnew file mode 100644 index 0000000..60f2ccb --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line1.gif diff --git a/funcweb/funcweb/static/images/imgs/line1_rtl.gif b/funcweb/funcweb/static/images/imgs/line1_rtl.gif Binary files differnew file mode 100644 index 0000000..96db473 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line1_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/line2.gif b/funcweb/funcweb/static/images/imgs/line2.gif Binary files differnew file mode 100644 index 0000000..f2d7bdd --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line2.gif diff --git a/funcweb/funcweb/static/images/imgs/line2_rtl.gif b/funcweb/funcweb/static/images/imgs/line2_rtl.gif Binary files differnew file mode 100644 index 0000000..5e6c6fc --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line2_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/line3.gif b/funcweb/funcweb/static/images/imgs/line3.gif Binary files differnew file mode 100644 index 0000000..d718be2 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line3.gif diff --git a/funcweb/funcweb/static/images/imgs/line3_rtl.gif b/funcweb/funcweb/static/images/imgs/line3_rtl.gif Binary files differnew file mode 100644 index 0000000..df7f5d8 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line3_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/line4.gif b/funcweb/funcweb/static/images/imgs/line4.gif Binary files differnew file mode 100644 index 0000000..29285e5 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line4.gif diff --git a/funcweb/funcweb/static/images/imgs/line4_rtl.gif b/funcweb/funcweb/static/images/imgs/line4_rtl.gif Binary files differnew file mode 100644 index 0000000..6c97452 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/line4_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/lock.gif b/funcweb/funcweb/static/images/imgs/lock.gif Binary files differnew file mode 100644 index 0000000..1d06b0d --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/lock.gif diff --git a/funcweb/funcweb/static/images/imgs/minus.gif b/funcweb/funcweb/static/images/imgs/minus.gif Binary files differnew file mode 100644 index 0000000..ef04a54 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus.gif diff --git a/funcweb/funcweb/static/images/imgs/minus2.gif b/funcweb/funcweb/static/images/imgs/minus2.gif Binary files differnew file mode 100644 index 0000000..0372294 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus2.gif diff --git a/funcweb/funcweb/static/images/imgs/minus2_rtl.gif b/funcweb/funcweb/static/images/imgs/minus2_rtl.gif Binary files differnew file mode 100644 index 0000000..521c2bf --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus2_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/minus3.gif b/funcweb/funcweb/static/images/imgs/minus3.gif Binary files differnew file mode 100644 index 0000000..d928af6 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus3.gif diff --git a/funcweb/funcweb/static/images/imgs/minus3_rtl.gif b/funcweb/funcweb/static/images/imgs/minus3_rtl.gif Binary files differnew file mode 100644 index 0000000..837f7c3 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus3_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/minus4.gif b/funcweb/funcweb/static/images/imgs/minus4.gif Binary files differnew file mode 100644 index 0000000..30bc7de --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus4.gif diff --git a/funcweb/funcweb/static/images/imgs/minus4_rtl.gif b/funcweb/funcweb/static/images/imgs/minus4_rtl.gif Binary files differnew file mode 100644 index 0000000..6dd9fbe --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus4_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/minus5.gif b/funcweb/funcweb/static/images/imgs/minus5.gif Binary files differnew file mode 100644 index 0000000..e2e30fc --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus5.gif diff --git a/funcweb/funcweb/static/images/imgs/minus5_rtl.gif b/funcweb/funcweb/static/images/imgs/minus5_rtl.gif Binary files differnew file mode 100644 index 0000000..ae0885b --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus5_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/minus_ar.gif b/funcweb/funcweb/static/images/imgs/minus_ar.gif Binary files differnew file mode 100644 index 0000000..4428ba1 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/minus_ar.gif diff --git a/funcweb/funcweb/static/images/imgs/plus.gif b/funcweb/funcweb/static/images/imgs/plus.gif Binary files differnew file mode 100644 index 0000000..abb84bd --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus.gif diff --git a/funcweb/funcweb/static/images/imgs/plus2.gif b/funcweb/funcweb/static/images/imgs/plus2.gif Binary files differnew file mode 100644 index 0000000..ea2816e --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus2.gif diff --git a/funcweb/funcweb/static/images/imgs/plus2_rtl.gif b/funcweb/funcweb/static/images/imgs/plus2_rtl.gif Binary files differnew file mode 100644 index 0000000..f1ba582 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus2_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/plus3.gif b/funcweb/funcweb/static/images/imgs/plus3.gif Binary files differnew file mode 100644 index 0000000..cd6967e --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus3.gif diff --git a/funcweb/funcweb/static/images/imgs/plus3_rtl.gif b/funcweb/funcweb/static/images/imgs/plus3_rtl.gif Binary files differnew file mode 100644 index 0000000..b8cad18 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus3_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/plus4.gif b/funcweb/funcweb/static/images/imgs/plus4.gif Binary files differnew file mode 100644 index 0000000..185bd9b --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus4.gif diff --git a/funcweb/funcweb/static/images/imgs/plus4_rtl.gif b/funcweb/funcweb/static/images/imgs/plus4_rtl.gif Binary files differnew file mode 100644 index 0000000..ce882e4 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus4_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/plus5.gif b/funcweb/funcweb/static/images/imgs/plus5.gif Binary files differnew file mode 100644 index 0000000..72fe4e5 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus5.gif diff --git a/funcweb/funcweb/static/images/imgs/plus5_rtl.gif b/funcweb/funcweb/static/images/imgs/plus5_rtl.gif Binary files differnew file mode 100644 index 0000000..15455b5 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus5_rtl.gif diff --git a/funcweb/funcweb/static/images/imgs/plus_ar.gif b/funcweb/funcweb/static/images/imgs/plus_ar.gif Binary files differnew file mode 100644 index 0000000..d2fcaf0 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/plus_ar.gif diff --git a/funcweb/funcweb/static/images/imgs/radio_off.gif b/funcweb/funcweb/static/images/imgs/radio_off.gif Binary files differnew file mode 100644 index 0000000..27dc5f9 --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/radio_off.gif diff --git a/funcweb/funcweb/static/images/imgs/radio_on.gif b/funcweb/funcweb/static/images/imgs/radio_on.gif Binary files differnew file mode 100644 index 0000000..efd74ee --- /dev/null +++ b/funcweb/funcweb/static/images/imgs/radio_on.gif diff --git a/funcweb/funcweb/static/images/removebtn.jpg b/funcweb/funcweb/static/images/removebtn.jpg Binary files differnew file mode 100644 index 0000000..f790fc7 --- /dev/null +++ b/funcweb/funcweb/static/images/removebtn.jpg diff --git a/funcweb/funcweb/static/images/removebtnhover.jpg b/funcweb/funcweb/static/images/removebtnhover.jpg Binary files differnew file mode 100644 index 0000000..eef98b8 --- /dev/null +++ b/funcweb/funcweb/static/images/removebtnhover.jpg 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=" "; 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', {"loading": null, "confirm": null, "after": null, "on_complete": null, "loaded": null, "on_failure": null, "on_success": null, "before":"myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide();"});" 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() |