init
authorAlan Knowles <alan@akbkhome.com>
Mon, 12 Apr 2010 09:10:57 +0000 (17:10 +0800)
committerAlan Knowles <alan@akbkhome.com>
Mon, 12 Apr 2010 09:10:57 +0000 (17:10 +0800)
60 files changed:
Core.perms.json [new file with mode: 0644]
Core.readers.js [new file with mode: 0644]
Core.translation.json [new file with mode: 0644]
DataObjects/Companies.php [new file with mode: 0644]
DataObjects/Events.php [new file with mode: 0644]
DataObjects/Group_Members.php [new file with mode: 0755]
DataObjects/Group_Rights.php [new file with mode: 0755]
DataObjects/Groups.php [new file with mode: 0755]
DataObjects/I18n.php [new file with mode: 0644]
DataObjects/Images.php [new file with mode: 0644]
DataObjects/Office.php [new file with mode: 0644]
DataObjects/Person.php [new file with mode: 0644]
DataObjects/Proftp_groups.php [new file with mode: 0644]
DataObjects/Projects.php [new file with mode: 0644]
DataObjects/Translations.php [new file with mode: 0644]
DataObjects/core.sql [new file with mode: 0644]
DataObjects/pman.ini [new file with mode: 0644]
DataObjects/pman.links.ini [new file with mode: 0644]
GroupMembers.php [new file with mode: 0644]
Pman.Dialog.Companies.js [new file with mode: 0644]
Pman.Dialog.Document_Types.js [new file with mode: 0644]
Pman.Dialog.Image.js [new file with mode: 0644]
Pman.Dialog.Office.js [new file with mode: 0644]
Pman.Dialog.Person.js [new file with mode: 0644]
Pman.Dialog.PersonEdit.js [new file with mode: 0644]
Pman.Dialog.PersonEditor.js [new file with mode: 0644]
Pman.Dialog.PersonNew.js [new file with mode: 0644]
Pman.Dialog.PersonStaff.js [new file with mode: 0644]
Pman.Dialog.Projects.js [new file with mode: 0644]
Pman.I18n.js [new file with mode: 0644]
Pman.Login.js [new file with mode: 0644]
Pman.PasswordChange.js [new file with mode: 0644]
Pman.Preview.js [new file with mode: 0644]
Pman.Remarks.js [new file with mode: 0644]
Pman.Std.js [new file with mode: 0644]
Pman.Tab.GroupsList.js [new file with mode: 0644]
Pman.Tab.PersonList.js [new file with mode: 0644]
Pman.js [new file with mode: 0644]
SendIntro.php [new file with mode: 0644]
SimpleExcel.php [new file with mode: 0644]
UploadProgress.php [new file with mode: 0644]
compiled/Core.js [new file with mode: 0644]
compiled/_translation_.js [new file with mode: 0644]
core.css [new file with mode: 0644]
templates/master.html [new file with mode: 0644]
widgets/ActionBox.js [new file with mode: 0644]
widgets/ColorField.js [new file with mode: 0644]
widgets/ComboBoxAdder.js [new file with mode: 0644]
widgets/ComboBoxLister.js [new file with mode: 0644]
widgets/ContentPanel2.js [new file with mode: 0644]
widgets/DisplayImage.js [new file with mode: 0644]
widgets/DisplayText.js [new file with mode: 0644]
widgets/Document.js [new file with mode: 0644]
widgets/Ext.bugs.js [new file with mode: 0644]
widgets/FieldSetEx.js [new file with mode: 0644]
widgets/FormGrid.js [new file with mode: 0644]
widgets/GnumericWriter.js [new file with mode: 0644]
widgets/SecurePass.js [new file with mode: 0644]
widgets/StarField.js [new file with mode: 0644]
widgets/lib.translation.json [new file with mode: 0644]

diff --git a/Core.perms.json b/Core.perms.json
new file mode 100644 (file)
index 0000000..43b1ac7
--- /dev/null
@@ -0,0 +1,24 @@
+
+{      
+       "/Permission Name"   :  "/ full perms (Default admin),    default perms) , description",
+        
+          
+       "Projects_Member_Of"      : [ "EPS",     "S" , "Can only See projects they are member of" ] ,
+       "Projects_All"            : [ "ADEPS",   "" , "Can see All Projects"] ,
+        
+        
+       "Document_Types"            : [ "ADEPS",  "S" , "Document Types"] ,
+        
+       "Person"                    : [ "ADEPS", "S" , "Contacts"] ,
+       "Offices"                   : [ "ADEPS", "S" , "Contact Offices"] ,
+       "Companies"                 : [ "ADEPS", "S" , "Contact Companies"] ,
+        
+       "Staff"                     : [ "ADEPS", "S" , "Staff"] ,
+       "Groups"                    : [ "ADEPS", "" , "Group Management"] ,
+        
+       "Events"                    : [ "PS",     "", "Event Log"] 
+}
+            
+            
+            
\ No newline at end of file
diff --git a/Core.readers.js b/Core.readers.js
new file mode 100644 (file)
index 0000000..2e12e88
--- /dev/null
@@ -0,0 +1,493 @@
+//<script type="text/javascript">
+
+Pman.Readers.Companies = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               'code',
+               'name',
+               'remarks',
+               {name : 'owner_id',type : 'int'},
+               'address',
+               'tel',
+               'fax',
+               'email',
+               {name : 'id',type : 'int'},
+               {name : 'isOwner',type : 'int'},
+               {name : 'logo_id',type : 'int'},
+               'background_color',
+               'comptype',
+               'ava_craft',
+               'url',
+               {name : 'main_office_id',type : 'int'},
+               {name : 'created_by',type : 'int'},
+               {name : 'created_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               {name : 'updated_by',type : 'int'},
+               {name : 'updated_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'passwd',
+               {name : 'logo_id_id',type : 'int'},
+               'logo_id_filename',
+               'logo_id_ontable',
+               {name : 'logo_id_onid',type : 'int'},
+               'logo_id_mimetype',
+               {name : 'logo_id_width',type : 'int'},
+               {name : 'logo_id_height',type : 'int'},
+               {name : 'logo_id_filesize',type : 'int'},
+               {name : 'logo_id_displayorder',type : 'int'},
+               'logo_id_language',
+               {name : 'logo_id_parent_image_id',type : 'int'},
+               {name : 'logo_id_created',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'logo_id_imgtype',
+               'logo_id_linkurl',
+               'logo_id_descript',
+               'logo_id_title',
+               {name : 'owner_id_id',type : 'int'},
+               {name : 'owner_id_office_id',type : 'int'},
+               'owner_id_name',
+               'owner_id_phone',
+               'owner_id_fax',
+               'owner_id_email',
+               {name : 'owner_id_company_id',type : 'int'},
+               'owner_id_role',
+               {name : 'owner_id_active',type : 'int'},
+               'owner_id_remarks',
+               'owner_id_passwd',
+               {name : 'owner_id_owner_id',type : 'int'},
+               'owner_id_lang',
+               {name : 'owner_id_no_reset_sent',type : 'int'},
+               {name : 'owner_id_project_id',type : 'int'},
+               'owner_id_action_type',
+               {name : 'main_office_id_id',type : 'int'},
+               {name : 'main_office_id_company_id',type : 'int'},
+               'main_office_id_name',
+               'main_office_id_address',
+               'main_office_id_phone',
+               'main_office_id_fax',
+               'main_office_id_email',
+               'main_office_id_role'
+       ]
+};
+
+Pman.Readers.Events = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               'person_name',
+               {name : 'event_when',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'action',
+               'ipaddr',
+               {name : 'on_id',type : 'int'},
+               'on_table',
+               {name : 'person_id',type : 'int'},
+               'remarks',
+               {name : 'person_id_id',type : 'int'},
+               {name : 'person_id_office_id',type : 'int'},
+               'person_id_name',
+               'person_id_phone',
+               'person_id_fax',
+               'person_id_email',
+               {name : 'person_id_company_id',type : 'int'},
+               'person_id_role',
+               {name : 'person_id_active',type : 'int'},
+               'person_id_remarks',
+               'person_id_passwd',
+               {name : 'person_id_owner_id',type : 'int'},
+               'person_id_lang',
+               {name : 'person_id_no_reset_sent',type : 'int'},
+               {name : 'person_id_project_id',type : 'int'},
+               'person_id_action_type'
+       ]
+};
+
+Pman.Readers.Group_Members = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'group_id',type : 'int'},
+               {name : 'id',type : 'int'},
+               {name : 'user_id',type : 'int'},
+               {name : 'group_id_id',type : 'int'},
+               'group_id_name',
+               {name : 'group_id_type',type : 'int'},
+               {name : 'group_id_leader',type : 'int'},
+               {name : 'user_id_id',type : 'int'},
+               {name : 'user_id_office_id',type : 'int'},
+               'user_id_name',
+               'user_id_phone',
+               'user_id_fax',
+               'user_id_email',
+               {name : 'user_id_company_id',type : 'int'},
+               'user_id_role',
+               {name : 'user_id_active',type : 'int'},
+               'user_id_remarks',
+               'user_id_passwd',
+               {name : 'user_id_owner_id',type : 'int'},
+               'user_id_lang',
+               {name : 'user_id_no_reset_sent',type : 'int'},
+               {name : 'user_id_project_id',type : 'int'},
+               'user_id_action_type'
+       ]
+};
+
+Pman.Readers.Group_Rights = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               'rightname',
+               {name : 'group_id',type : 'int'},
+               'AccessMask',
+               {name : 'id',type : 'int'},
+               {name : 'group_id_id',type : 'int'},
+               'group_id_name',
+               {name : 'group_id_type',type : 'int'},
+               {name : 'group_id_leader',type : 'int'}
+       ]
+};
+
+Pman.Readers.Groups = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               'name',
+               {name : 'type',type : 'int'},
+               {name : 'leader',type : 'int'},
+               {name : 'leader_id',type : 'int'},
+               {name : 'leader_office_id',type : 'int'},
+               'leader_name',
+               'leader_phone',
+               'leader_fax',
+               'leader_email',
+               {name : 'leader_company_id',type : 'int'},
+               'leader_role',
+               {name : 'leader_active',type : 'int'},
+               'leader_remarks',
+               'leader_passwd',
+               {name : 'leader_owner_id',type : 'int'},
+               'leader_lang',
+               {name : 'leader_no_reset_sent',type : 'int'},
+               {name : 'leader_project_id',type : 'int'},
+               'leader_action_type'
+       ]
+};
+
+Pman.Readers.Images = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               'filename',
+               'ontable',
+               {name : 'onid',type : 'int'},
+               'mimetype',
+               {name : 'width',type : 'int'},
+               {name : 'height',type : 'int'},
+               {name : 'filesize',type : 'int'},
+               {name : 'displayorder',type : 'int'},
+               'language',
+               {name : 'parent_image_id',type : 'int'},
+               {name : 'created',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'imgtype',
+               'linkurl',
+               'descript',
+               'title',
+               {name : 'parent_image_id_id',type : 'int'},
+               'parent_image_id_filename',
+               'parent_image_id_ontable',
+               {name : 'parent_image_id_onid',type : 'int'},
+               'parent_image_id_mimetype',
+               {name : 'parent_image_id_width',type : 'int'},
+               {name : 'parent_image_id_height',type : 'int'},
+               {name : 'parent_image_id_filesize',type : 'int'},
+               {name : 'parent_image_id_displayorder',type : 'int'},
+               'parent_image_id_language',
+               {name : 'parent_image_id_parent_image_id',type : 'int'},
+               {name : 'parent_image_id_created',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'parent_image_id_imgtype',
+               'parent_image_id_linkurl',
+               'parent_image_id_descript',
+               'parent_image_id_title'
+       ]
+};
+
+Pman.Readers.Office = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               {name : 'company_id',type : 'int'},
+               'name',
+               'address',
+               'phone',
+               'fax',
+               'email',
+               'role',
+               'company_id_code',
+               'company_id_name',
+               'company_id_remarks',
+               {name : 'company_id_owner_id',type : 'int'},
+               'company_id_address',
+               'company_id_tel',
+               'company_id_fax',
+               'company_id_email',
+               {name : 'company_id_id',type : 'int'},
+               {name : 'company_id_isOwner',type : 'int'},
+               {name : 'company_id_logo_id',type : 'int'},
+               'company_id_background_color',
+               'company_id_comptype',
+               'company_id_ava_craft',
+               'company_id_url',
+               {name : 'company_id_main_office_id',type : 'int'},
+               {name : 'company_id_created_by',type : 'int'},
+               {name : 'company_id_created_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               {name : 'company_id_updated_by',type : 'int'},
+               {name : 'company_id_updated_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'company_id_passwd'
+       ]
+};
+
+Pman.Readers.Person = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               {name : 'office_id',type : 'int'},
+               'name',
+               'phone',
+               'fax',
+               'email',
+               {name : 'company_id',type : 'int'},
+               'role',
+               {name : 'active',type : 'int'},
+               'remarks',
+               'passwd',
+               {name : 'owner_id',type : 'int'},
+               'lang',
+               {name : 'no_reset_sent',type : 'int'},
+               {name : 'project_id',type : 'int'},
+               'action_type',
+               {name : 'office_id_id',type : 'int'},
+               {name : 'office_id_company_id',type : 'int'},
+               'office_id_name',
+               'office_id_address',
+               'office_id_phone',
+               'office_id_fax',
+               'office_id_email',
+               'office_id_role',
+               'company_id_code',
+               'company_id_name',
+               'company_id_remarks',
+               {name : 'company_id_owner_id',type : 'int'},
+               'company_id_address',
+               'company_id_tel',
+               'company_id_fax',
+               'company_id_email',
+               {name : 'company_id_id',type : 'int'},
+               {name : 'company_id_isOwner',type : 'int'},
+               {name : 'company_id_logo_id',type : 'int'},
+               'company_id_background_color',
+               'company_id_comptype',
+               'company_id_ava_craft',
+               'company_id_url',
+               {name : 'company_id_main_office_id',type : 'int'},
+               {name : 'company_id_created_by',type : 'int'},
+               {name : 'company_id_created_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               {name : 'company_id_updated_by',type : 'int'},
+               {name : 'company_id_updated_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'company_id_passwd',
+               {name : 'project_id_id',type : 'int'},
+               'project_id_name',
+               'project_id_remarks',
+               {name : 'project_id_owner_id',type : 'int'},
+               'project_id_code',
+               {name : 'project_id_active',type : 'int'},
+               'project_id_type',
+               {name : 'project_id_client_id',type : 'int'},
+               {name : 'project_id_team_id',type : 'int'},
+               'project_id_file_location',
+               {name : 'project_id_open_date',type : 'date',dateFormat : 'Y-m-d'},
+               {name : 'project_id_open_by',type : 'int'},
+               'project_id_countries',
+               'project_id_languages',
+               {name : 'project_id_close_date',type : 'date',dateFormat : 'Y-m-d'},
+               {name : 'project_id_agency_id',type : 'int'},
+               {name : 'owner_id_id',type : 'int'},
+               {name : 'owner_id_office_id',type : 'int'},
+               'owner_id_name',
+               'owner_id_phone',
+               'owner_id_fax',
+               'owner_id_email',
+               {name : 'owner_id_company_id',type : 'int'},
+               'owner_id_role',
+               {name : 'owner_id_active',type : 'int'},
+               'owner_id_remarks',
+               'owner_id_passwd',
+               {name : 'owner_id_owner_id',type : 'int'},
+               'owner_id_lang',
+               {name : 'owner_id_no_reset_sent',type : 'int'},
+               {name : 'owner_id_project_id',type : 'int'},
+               'owner_id_action_type'
+       ]
+};
+
+Pman.Readers.Projects = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               'name',
+               'remarks',
+               {name : 'owner_id',type : 'int'},
+               'code',
+               {name : 'active',type : 'int'},
+               'type',
+               {name : 'client_id',type : 'int'},
+               {name : 'team_id',type : 'int'},
+               'file_location',
+               {name : 'open_date',type : 'date',dateFormat : 'Y-m-d'},
+               {name : 'open_by',type : 'int'},
+               'countries',
+               'languages',
+               {name : 'close_date',type : 'date',dateFormat : 'Y-m-d'},
+               {name : 'agency_id',type : 'int'},
+               'client_id_code',
+               'client_id_name',
+               'client_id_remarks',
+               {name : 'client_id_owner_id',type : 'int'},
+               'client_id_address',
+               'client_id_tel',
+               'client_id_fax',
+               'client_id_email',
+               {name : 'client_id_id',type : 'int'},
+               {name : 'client_id_isOwner',type : 'int'},
+               {name : 'client_id_logo_id',type : 'int'},
+               'client_id_background_color',
+               'client_id_comptype',
+               'client_id_ava_craft',
+               'client_id_url',
+               {name : 'client_id_main_office_id',type : 'int'},
+               {name : 'client_id_created_by',type : 'int'},
+               {name : 'client_id_created_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               {name : 'client_id_updated_by',type : 'int'},
+               {name : 'client_id_updated_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'client_id_passwd',
+               'agency_id_code',
+               'agency_id_name',
+               'agency_id_remarks',
+               {name : 'agency_id_owner_id',type : 'int'},
+               'agency_id_address',
+               'agency_id_tel',
+               'agency_id_fax',
+               'agency_id_email',
+               {name : 'agency_id_id',type : 'int'},
+               {name : 'agency_id_isOwner',type : 'int'},
+               {name : 'agency_id_logo_id',type : 'int'},
+               'agency_id_background_color',
+               'agency_id_comptype',
+               'agency_id_ava_craft',
+               'agency_id_url',
+               {name : 'agency_id_main_office_id',type : 'int'},
+               {name : 'agency_id_created_by',type : 'int'},
+               {name : 'agency_id_created_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               {name : 'agency_id_updated_by',type : 'int'},
+               {name : 'agency_id_updated_dt',type : 'date',dateFormat : 'Y-m-d H:i:s'},
+               'agency_id_passwd',
+               {name : 'team_id_id',type : 'int'},
+               'team_id_name',
+               {name : 'team_id_type',type : 'int'},
+               {name : 'team_id_leader',type : 'int'},
+               {name : 'open_by_id',type : 'int'},
+               {name : 'open_by_office_id',type : 'int'},
+               'open_by_name',
+               'open_by_phone',
+               'open_by_fax',
+               'open_by_email',
+               {name : 'open_by_company_id',type : 'int'},
+               'open_by_role',
+               {name : 'open_by_active',type : 'int'},
+               'open_by_remarks',
+               'open_by_passwd',
+               {name : 'open_by_owner_id',type : 'int'},
+               'open_by_lang',
+               {name : 'open_by_no_reset_sent',type : 'int'},
+               {name : 'open_by_project_id',type : 'int'},
+               'open_by_action_type',
+               {name : 'owner_id_id',type : 'int'},
+               {name : 'owner_id_office_id',type : 'int'},
+               'owner_id_name',
+               'owner_id_phone',
+               'owner_id_fax',
+               'owner_id_email',
+               {name : 'owner_id_company_id',type : 'int'},
+               'owner_id_role',
+               {name : 'owner_id_active',type : 'int'},
+               'owner_id_remarks',
+               'owner_id_passwd',
+               {name : 'owner_id_owner_id',type : 'int'},
+               'owner_id_lang',
+               {name : 'owner_id_no_reset_sent',type : 'int'},
+               {name : 'owner_id_project_id',type : 'int'},
+               'owner_id_action_type'
+       ]
+};
+
+Pman.Readers.I18n = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               'ltype',
+               'lkey',
+               'inlang',
+               'lval'
+       ]
+};
+
+Pman.Readers.Proftp_groups = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               {name : 'grpid',type : 'int'},
+               'grpname',
+               'grpmembers'
+       ]
+};
+
+Pman.Readers.Translations = {
+       root : 'data',
+       totalProperty : 'total',
+       id : 'id',
+       xtype : 'JsonReader',
+       fields : [
+               {name : 'id',type : 'int'},
+               'module',
+               'tfile',
+               'tlang',
+               'tkey',
+               'tval'
+       ]
+};
diff --git a/Core.translation.json b/Core.translation.json
new file mode 100644 (file)
index 0000000..305eebd
--- /dev/null
@@ -0,0 +1,308 @@
+
+"Pman.js" : {
+        "" : "",
+        " of " : " of ",
+        "Error" : "Error",
+        "Logout" : "Logout",
+        "Confirm" : "Confirm",
+        "Deleting" : "Deleting",
+        " (clean up) " : " (clean up) ",
+        "Add New Item" : "Add New Item",
+        "Error Sending" : "Error Sending",
+        "Error Deleting" : "Error Deleting",
+        "Error download" : "Error download",
+        "Please wait..." : "Please wait...",
+        "invalid in_out" : "invalid in_out",
+        "Change Password" : "Change Password",
+        "Building Interface " : "Building Interface ",
+        "Problem Loading Data" : "Problem Loading Data",
+        "Building Interface..." : "Building Interface...",
+        "Error loading details" : "Error loading details",
+        "Loading Document details" : "Loading Document details",
+        "Connection timed out sending" : "Connection timed out sending",
+        "Select at least one Row to delete" : "Select at least one Row to delete",
+        "Please Correct all the errors in red" : "Please Correct all the errors in red",
+        "Are you sure you want to delete that?" : "Are you sure you want to delete that?",
+        "You are Logged in as <b>{0} ({1})</b>" : "You are Logged in as <b>{0} ({1})</b>",
+        "Saving failed = fix errors and try again" : "Saving failed = fix errors and try again",
+        "Problem Connecting to Server - please try again." : "Problem Connecting to Server - please try again.",
+        "Closing this window will loose changes, are you sure you want to do that?" : "Closing this window will loose changes, are you sure you want to do that?"
+},
+"Pman.Std.js" : {
+        "To" : "To",
+        "Type" : "Type",
+        "Project" : "Project",
+        "Sent To" : "Sent To",
+        "Searching..." : "Searching...",
+        "Enter Sent To" : "Enter Sent To",
+        "Select Office" : "Select Office",
+        "Select Project" : "Select Project",
+        "Office / Department" : "Office / Department",
+        "Select Document Type" : "Select Document Type",
+        "Select an address to add." : "Select an address to add."
+},
+"Pman.I18n.js" : {
+        "Country" : "Country",
+        "Currency" : "Currency",
+        "Language" : "Language",
+        "Country(s)" : "Country(s)",
+        "Language(s)" : "Language(s)",
+        "Searching..." : "Searching...",
+        "Select Country" : "Select Country",
+        "Select Currency" : "Select Currency",
+        "Select Language" : "Select Language",
+        "Select a country to add." : "Select a country to add.",
+        "Select a language to add." : "Select a language to add."
+},
+"Pman.Login.js" : {
+        "20" : "20",
+        "text" : "text",
+        "Error" : "Error",
+        "Login" : "Login",
+        "Sorry" : "Sorry",
+        "input" : "input",
+        "Notice" : "Notice",
+        "Warning" : "Warning",
+        "Language" : "Language",
+        "Password" : "Password",
+        "Logging in" : "Logging in",
+        "Email Address" : "Email Address",
+        "Forgot Password" : "Forgot Password",
+        "Fill in your email address" : "Fill in your email address",
+        "Language not available yet (" : "Language not available yet (",
+        "Problem Requesting Password Reset" : "Problem Requesting Password Reset",
+        "Error logging out. - continuing anyway." : "Error logging out. - continuing anyway.",
+        "Login failed - communication error - try again." : "Login failed - communication error - try again.",
+        "Error getting authentication status. - try reloading" : "Error getting authentication status. - try reloading",
+        "Please check you email for the Password Reset message" : "Please check you email for the Password Reset message",
+        "This is an open system - please set up a admin user with a password." : "This is an open system - please set up a admin user with a password.",
+        "Error getting authentication status. - try reloading, or wait a while" : "Error getting authentication status. - try reloading, or wait a while"
+},
+"Pman.Preview.js" : {
+        "Click to view PDF" : "Click to view PDF"
+},
+"Pman.Dialog.Image.js" : {
+        "Save" : "Save",
+        "Error" : "Error",
+        "Cancel" : "Cancel",
+        "Sending" : "Sending",
+        "Uploading" : "Uploading",
+        "Upload Image or File" : "Upload Image or File",
+        "Error loading details" : "Error loading details",
+        "Upload Image or  File" : "Upload Image or  File",
+        "Saving failed = fix errors and try again" : "Saving failed = fix errors and try again"
+},
+"Pman.Dialog.Person.js" : {
+        "Edit Contact Details" : "Edit Contact Details"
+},
+"Pman.Dialog.Office.js" : {
+        "fax" : "fax",
+        "Save" : "Save",
+        "Email" : "Email",
+        "Phone" : "Phone",
+        "Cancel" : "Cancel",
+        "Address" : "Address",
+        "Company" : "Company",
+        "Enter fax" : "Enter fax",
+        "Enter name" : "Enter name",
+        "Enter email" : "Enter email",
+        "Enter phone" : "Enter phone",
+        "Enter address" : "Enter address",
+        "Office / Department / Sub Comp. Name" : "Office / Department / Sub Comp. Name",
+        "Edit Office / Department / Sub Company" : "Edit Office / Department / Sub Company"
+},
+"Pman.Tab.GroupsList.js" : {
+        "Add" : "Add",
+        "Edit" : "Edit",
+        "Name" : "Name",
+        "Error" : "Error",
+        "Delete" : "Delete",
+        "Reload" : "Reload",
+        "All Staff" : "All Staff",
+        "Everybody" : "Everybody",
+        "Select a Row" : "Select a Row",
+        "Adminstrators" : "Adminstrators",
+        "Manage Groups" : "Manage Groups",
+        "Not in a Group" : "Not in a Group",
+        "Select only one Row" : "Select only one Row",
+        "You can not delete that group" : "You can not delete that group",
+        "You can not rename that group" : "You can not rename that group",
+        "All Staff (Default Permissions)" : "All Staff (Default Permissions)"
+},
+"Pman.Tab.PersonList.js" : {
+        "Add" : "Add",
+        "Fax" : "Fax",
+        "No " : "No ",
+        "Edit" : "Edit",
+        "Name" : "Name",
+        "Email" : "Email",
+        "Error" : "Error",
+        "Phone" : "Phone",
+        "Staff" : "Staff",
+        " found" : " found",
+        "Active" : "Active",
+        "Delete" : "Delete",
+        "Search" : "Search",
+        "Project" : "Project",
+        "Sending" : "Sending",
+        "Bulk Add" : "Bulk Add",
+        "Displaying " : "Displaying ",
+        "Company Type" : "Company Type",
+        "Reset Search" : "Reset Search",
+        "Select a Row" : "Select a Row",
+        "Error Sending" : "Error Sending",
+        "Toogle Active" : "Toogle Active",
+        "Hide old staff" : "Hide old staff",
+        "Office / Dept." : "Office / Dept.",
+        "Show old staff" : "Show old staff",
+        "Role / Position" : "Role / Position",
+        "Company / Office" : "Company / Office",
+        " {0} - {1} of {2}" : " {0} - {1} of {2}",
+        "Select People Row" : "Select People Row",
+        "Select only one Row" : "Select only one Row",
+        "Drag person to add or remove from team" : "Drag person to add or remove from team",
+        "Drag person to add or remove from group" : "Drag person to add or remove from group"
+},
+"Pman.PasswordChange.js" : {
+        "Save" : "Save",
+        "Error" : "Error",
+        "Cancel" : "Cancel",
+        "New Password " : "New Password ",
+        "Change Password" : "Change Password",
+        "Error loading details" : "Error loading details",
+        "Passwords do not match" : "Passwords do not match",
+        "Enter Passwords in both boxes" : "Enter Passwords in both boxes",
+        "Please Correct all the errors" : "Please Correct all the errors",
+        "New Password (type again to confirm)" : "New Password (type again to confirm)",
+        "Saving failed = fix errors and try again" : "Saving failed = fix errors and try again"
+},
+"Pman.Dialog.Projects.js" : {
+        "" : "",
+        "By" : "By",
+        "Code" : "Code",
+        "Date" : "Date",
+        "Save" : "Save",
+        "Team" : "Team",
+        "Cancel" : "Cancel",
+        "Client" : "Client",
+        "Remarks" : "Remarks",
+        "Select Team" : "Select Team",
+        "Edit Project" : "Edit Project",
+        "Project Name" : "Project Name",
+        "Project type" : "Project type",
+        "Searching..." : "Searching...",
+        "File Location" : "File Location",
+        "Select Client" : "Select Client",
+        "Enter Date Opened" : "Enter Date Opened",
+        "Enter Project Code" : "Enter Project Code",
+        "Enter Project Name" : "Enter Project Name",
+        "Enter Project Remarks" : "Enter Project Remarks",
+        "Select Person Who opened" : "Select Person Who opened",
+        "Where are the files stored?" : "Where are the files stored?"
+},
+"Pman.Dialog.PersonNew.js" : {
+        "New Contact Details" : "New Contact Details"
+},
+"Pman.Dialog.Companies.js" : {
+        "fax" : "fax",
+        "Save" : "Save",
+        "Email" : "Email",
+        "OWNER" : "OWNER",
+        "Phone" : "Phone",
+        "Cancel" : "Cancel",
+        "Client" : "Client",
+        "Address" : "Address",
+        "Loading" : "Loading",
+        "Remarks" : "Remarks",
+        "Consultant" : "Consultant",
+        "Contractor" : "Contractor",
+        "Enter code" : "Enter code",
+        "Logo Image" : "Logo Image",
+        "Add Company" : "Add Company",
+        "Select Type" : "Select Type",
+        "Company Name" : "Company Name",
+        "Edit Company" : "Edit Company",
+        "System Owner" : "System Owner",
+        "Upload Image" : "Upload Image",
+        "Enter Address" : "Enter Address",
+        "Enter remarks" : "Enter remarks",
+        "Edit Companies" : "Edit Companies",
+        "Enter fax Number" : "Enter fax Number",
+        "Background Colour" : "Background Colour",
+        "No Image Attached" : "No Image Attached",
+        "Add / Change Image" : "Add / Change Image",
+        "Change / Add Image" : "Change / Add Image",
+        "Enter Company Name" : "Enter Company Name",
+        "Enter Phone Number" : "Enter Phone Number",
+        "No Image Available" : "No Image Available",
+        "Enter Email Address" : "Enter Email Address",
+        "Your Company Details" : "Your Company Details",
+        "Company ID (for filing Ref.)" : "Company ID (for filing Ref.)"
+},
+"Pman.Dialog.PersonEdit.js" : {
+        "Edit Contact Details" : "Edit Contact Details"
+},
+"Pman.Dialog.PersonStaff.js" : {
+        "Add / Edit Staff" : "Add / Edit Staff"
+},
+"Pman.Dialog.PersonEditor.js" : {
+        "No" : "No",
+        "\n" : "\n",
+        " : " : " : ",
+        "Fax" : "Fax",
+        "Yes" : "Yes",
+        "Done" : "Done",
+        "Save" : "Save",
+        "Email" : "Email",
+        "Error" : "Error",
+        "Phone" : "Phone",
+        "Cancel" : "Cancel",
+        "Office" : "Office",
+        "Company" : "Company",
+        "Done - " : "Done - ",
+        "Loading" : "Loading",
+        "Project" : "Project",
+        "Sending" : "Sending",
+        "Enter fax" : "Enter fax",
+        "Enter name" : "Enter name",
+        "Action Type" : "Action Type",
+        "Enter email" : "Enter email",
+        "Contact Name" : "Contact Name",
+        "Searching..." : "Searching...",
+        "Send Welcome" : "Send Welcome",
+        "New Password " : "New Password ",
+        "Select Office" : "Select Office",
+        "Please wait..." : "Please wait...",
+        "Select Company" : "Select Company",
+        "Action Required" : "Action Required",
+        "Role / Position" : "Role / Position",
+        "Select a Company" : "Select a Company",
+        "Enter phone Number" : "Enter phone Number",
+        "No addresses found" : "No addresses found",
+        "Office / Department" : "Office / Department",
+        "Enter email addresse" : "Enter email addresse",
+        "Enter Role / Position" : "Enter Role / Position",
+        "Passwords do not match" : "Passwords do not match",
+        "Send Introduction Mail" : "Send Introduction Mail",
+        "Select An Company First" : "Select An Company First",
+        "Select the Company Name" : "Select the Company Name",
+        "Sending Welcome Message" : "Sending Welcome Message",
+        "Email address (one per line)" : "Email address (one per line)",
+        "Password (type again to confirm)" : "Password (type again to confirm)",
+        "Creating Account / Sending Welcome" : "Creating Account / Sending Welcome",
+        "Send Welcome Messages and Generate Passwords?" : "Send Welcome Messages and Generate Passwords?",
+        "Always File Messages from this Person in Project" : "Always File Messages from this Person in Project",
+        "You must create a password for the admin account" : "You must create a password for the admin account",
+        "You must create a password to send introduction mail" : "You must create a password to send introduction mail"
+},
+"Pman.Dialog.Document_Types.js" : {
+        "Code" : "Code",
+        "Save" : "Save",
+        "Cancel" : "Cancel",
+        "Remarks" : "Remarks",
+        "Enter code" : "Enter code",
+        "Document Type" : "Document Type",
+        "Enter remarks" : "Enter remarks",
+        "Edit Document Type" : "Edit Document Type",
+        "Enter Document Type" : "Enter Document Type"
+},
\ No newline at end of file
diff --git a/DataObjects/Companies.php b/DataObjects/Companies.php
new file mode 100644 (file)
index 0000000..6ddcbca
--- /dev/null
@@ -0,0 +1,271 @@
+<?php
+/**
+ * Table Definition for Companies
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Companies extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Companies';                       // table name
+    public $code;                            // string(32)  not_null
+    public $name;                            // string(128)  multiple_key
+    public $remarks;                         // blob(65535)  blob
+    public $owner_id;                        // int(11)  not_null
+    public $address;                         // blob(65535)  blob
+    public $tel;                             // string(32)  
+    public $fax;                             // string(32)  
+    public $email;                           // string(128)  
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $isOwner;                         // int(11)  
+    public $logo_id;                         // int(11)  not_null
+    public $background_color;                // string(8)  not_null
+    public $comptype;                        // string(8)  not_null
+    public $ava_craft;                       // string(254)  
+    public $url;                             // string(254)  not_null
+    public $main_office_id;                  // int(11)  not_null
+    public $created_by;                      // int(11)  not_null
+    public $created_dt;                      // datetime(19)  not_null binary
+    public $updated_by;                      // int(11)  not_null
+    public $updated_dt;                      // datetime(19)  not_null binary
+    public $passwd;                          // string(64)  not_null
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    
+    function applyFilters($q, $au)
+    {
+        $x = DB_DataObject::factory('Companies');
+        $x->isOwner = 1;
+        $x->find(true);
+        
+        if (!empty($q['query']['company_project_id'])) {
+            $add = '';
+            if (!empty($q['query']['company_include_self'])) {
+                $add = ' OR Companies.id = ' . $x->id;
+            }
+            if (!empty($q['query']['company_not_self'])) {
+                $add = ' AND Companies.id != ' . $x->id;
+            }
+            $pids = array();
+            $pid = $q['query']['company_project_id'];
+            if (strpos($pid, ',')) {
+                $bits = explode(',', $pid);
+                foreach($bits as $b) {
+                    $pids[] = (int)$b;
+                }
+            } else {
+                $pids = array($pid);
+            }
+            
+            
+            $pids = implode(',', $pids);
+            $this->whereAdd("Companies.id IN (
+                SELECT distinct(company_id) FROM ProjectDirectory where project_id IN ($pids)
+            ) $add" );
+            
+           // DB_DataObject::debugLevel(1);
+            
+            
+        }
+        
+    }
+    function toEventString() {
+        return $this->name;
+    }
+    
+    // ---------- AUTHENTICATION
+     function isAuth()
+    {
+        $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        @session_start();
+        if (!empty($_SESSION[__CLASS__][$sesPrefix .'-auth'])) {
+            // in session...
+            $a = unserialize($_SESSION[__CLASS__][$sesPrefix .'-auth']);
+            $u = DB_DataObject::factory('Companies');
+            if ($u->get($a->id)) { //&& strlen($u->passwd)) {
+                return true;
+            }
+            $_SESSION[__CLASS__][$sesPrefix .'-auth'] = '';
+            
+        }
+        // not in session or not matched...
+        
+        
+        return false;
+        
+    }
+    function getAuthUser()
+    {
+        if (!$this->isAuth()) {
+            return false;
+        }
+        $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        if (!empty($_SESSION[__CLASS__][$sesPrefix .'-auth'])) {
+            $a = unserialize($_SESSION[__CLASS__][$sesPrefix .'-auth']);
+            
+            $u = DB_DataObject::factory('Companies');
+            if ($u->get($a->id)) { /// && strlen($u->passwd)) {
+                return clone($u);
+            }
+             
+        }
+        
+        
+        return false;
+    }     
+    function login()
+    {
+        $this->isAuth(); // force session start..
+         $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        $_SESSION[__CLASS__][$sesPrefix .'-auth'] = serialize($this);
+        
+    }
+    function logout()
+    {
+        $this->isAuth(); // force session start..
+        $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        $_SESSION[__CLASS__][$sesPrefix .'-auth'] = "";
+        
+    }    
+    // ---------- AUTHENTICATION
+    function checkPassword($val)
+    {
+        //echo '<pre>'.$val .  print_R($this,true);
+        if (substr($this->passwd,0,1) == '$') {
+            return crypt($val,$this->passwd) == $this->passwd ;
+        }
+        // old style md5 passwords...- cant be used with courier....
+        return md5($val) == $this->passwd;
+    }
+    function setPassword($value) 
+    {
+        $salt='';
+        while(strlen($salt)<9) {
+            $salt.=chr(rand(64,126));
+            //php -r var_dump(crypt('testpassword', '$1$'. (rand(64,126)). '$'));
+        }
+        $this->passwd = crypt($value, '$1$'. $salt. '$');
+       
+    }      
+    function onUpload($controller)
+    {
+        $image = DB_DataObject::factory('Images');
+        return $image->onUploadWithTbl($this, 'logo_id');
+         
+    }
+    function  onUpdate($old, $req,$roo) 
+    {
+        if (!empty($req['password1'])) {
+            $this->setPassword($req['password1']);
+            $this->update();
+        }
+    }
+    function onInsert($req, $roo)
+    {
+        if (!empty($this->logo_id)) { // update images table to sycn with this..
+            $img = DB_DataObject::factory('Images');
+            if ($img->get($this->logo_id) && ($img->onid != $this->id)) {
+                $img->onid = $this->id;
+                $img->update();
+            }
+        }
+        if (!empty($req['password1'])) {
+            $this->setPassword($req['password1']);
+            $this->update();
+        }
+        $img = DB_DataObject::factory('Images');
+        $img->onid= 0;
+        
+        $img->ontable = 'Companies';
+        $img->imgtype = 'LOGO';
+        // should check uploader!!!
+        if ($img->find()) {
+            while($img->fetch()) {
+                $ii = clone($img);
+                $ii->onid = $this->id;
+                $ii->update();
+                $this->logo_id = $ii->id;
+            }
+            $this->update();
+        }
+        
+        
+        
+        
+    }
+    
+    function beforeDelete()
+    {
+        // should check for members....
+        
+        $img = DB_DataObject::factory('Images');
+        $img->ontable = 'Companies';
+        $img->onid = $this->id;
+        $img->find();
+        while ($img->fetch()) {
+            $img->beforeDelete();
+            $img->delete();
+        }
+        return true;
+        
+         
+    }
+    /**
+     * check who is trying to access this. false == access denied..
+     */
+    function checkPerm($lvl, $au, $changes = false) 
+    {
+        if ($au->company()->comptype != 'OWNER') {
+            
+            // hacking!
+            if ($changes && isset($changes['comptype']) && $changes['comptype'] != $this->comptype) {
+                return false;
+            }
+            
+            return $this->id == $au->company_id;
+        }
+        
+        return $au->hasPerm("Core.".$this->tableName(), $lvl);    
+    } 
+    function whereAddIn($key, $list, $type= 'int') 
+    {
+        $ar = array();
+        foreach($list as $k) {
+            $ar[] = $type =='int' ? (int)$k : $this->escape($k);
+        }
+        if (!$ar) {
+            return;
+        }
+        return $this->whereAdd("$key IN (". implode(',', $ar). ')');
+    }
+    function fetchAll($k= false, $v = false) 
+    {
+        if ($k !== false) {
+            $this->selectAdd();
+            $this->selectAdd($k);
+            if ($v !== false) {
+                $this->selectAdd($v);
+            }
+        }
+        
+        $this->find();
+        $ret = array();
+        while ($this->fetch()) {
+            if ($v !== false) {
+                $ret[$this->$k] = $this->$v;
+                continue;
+            }
+            $ret[] = $k === false ? clone($this) : $this->$k;
+        }
+        return $ret;
+         
+    }
+}
diff --git a/DataObjects/Events.php b/DataObjects/Events.php
new file mode 100644 (file)
index 0000000..fce6342
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Table Definition for Events
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Events extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Events';                          // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $person_name;                     // string(128)  
+    public $event_when;                      // datetime(19)  binary
+    public $action;                          // string(32)  
+    public $ipaddr;                          // string(16)  
+    public $on_id;                           // int(11)  
+    public $on_table;                        // string(64)  
+    public $person_id;                       // int(11)  
+    public $remarks;                         // blob(65535)  blob
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    /**
+     * check who is trying to access this. false == access denied..
+     */
+    function checkPerm($lvl, $au) 
+    {
+        return $lvl == 'S' && $au->hasPerm("Admin.Admin_Tab", $lvl);
+    } 
+}
diff --git a/DataObjects/Group_Members.php b/DataObjects/Group_Members.php
new file mode 100755 (executable)
index 0000000..73a82b8
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Table Definition for Group_Members
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Group_Members extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Group_Members';                   // table name
+    public $group_id;                        // int(11)  
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $user_id;                         // int(11)  not_null
+
+  
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    
+    var $inAdmin = false;
+    function listGroupMembership($person, $arrayof = 'group_id') 
+    {
+        $this->inAdmin = false;
+        $t = clone($this);
+        //DB_DataObject::debugLevel(1);
+         
+        
+        $t->joinAdd(DB_DataObject::factory('Groups'), 'LEFT');
+        //$person->id = (int)$person->id;
+        $t->whereAdd("
+            user_id = {$person->id}
+        ");
+        $t->selectAdd();
+        $t->selectAdd('distinct(group_id), Groups.name as name');
+        
+        $t->find();
+        
+        $ret = $arrayof == 'group_id' ? array(0) : array(); // default member of 'All groups'!!
+        
+        while ($t->fetch()) {
+            $ret[] = $t->$arrayof;
+            if ($t->name == 'Administrators') { /// mmh... bit risky?
+                $this->inAdmin = true;
+            }
+        }
+        return $ret;
+        
+    }
+    function checkPerm($lvl, $au) 
+    {
+        return false;
+    } 
+    function fetchAll($k= false) {
+        if ($k !== false) {
+            $this->selectAdd();
+            $this->selectAdd($k);
+        }
+        
+        $this->find();
+        $ret = array();
+        while ($this->fetch()) {
+            $ret[] = $k === false ? clone($this) : $this->$k;
+        }
+        return $ret;
+         
+    }
+}
diff --git a/DataObjects/Group_Rights.php b/DataObjects/Group_Rights.php
new file mode 100755 (executable)
index 0000000..f3c67c9
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+/**
+ * Table Definition for Group_Rights
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Group_Rights extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Group_Rights';                    // table name
+    public $rightname;                       // string(64)  not_null
+    public $group_id;                        // int(11)  not_null
+    public $AccessMask;                      // string(10)  not_null
+    public $id;                              // int(11)  not_null primary_key auto_increment
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    
+    
+    var $fullRights = "ADESPIM";
+    
+    function listPermsFromGroupIds($grps, $isAdmin=false) {
+        
+        $t = clone($this);
+        $t->whereAdd('group_id IN ('. implode(',', $grps).')');
+        $t->find();
+        $ret = array();
+        while($t->fetch()) {
+            if (isset($ret[$t->rightname])) {
+                $ret[$t->rightname] = $this->mergeMask($ret[$t->rightname], $t->AccessMask);
+                continue;
+            }
+            $ret[$t->rightname] = $t->AccessMask;
+        }
+        // blank out rights that are disabled by the system..
+        $defs = $this->defaultPermData();
+        //echo "<PRE>";print_r($defs);
+        $r = array();
+        foreach($defs as $k=>$v) {
+            if (empty($v[0])) { // delete right if not there..
+                $r[$k] = '';
+                continue;
+            }
+            
+            
+            if (isset($ret[$k])) {
+                if (empty($ret[$k]) && $isAdmin) {
+                    $r[$k] = $v[0];
+                    continue;
+                }
+                
+                $r[$k] = $ret[$k];
+                continue;
+            }
+            // not set contition...
+            
+            $r[$k] = $isAdmin ? $v[0] : $v[1];
+            
+       
+        }
+        
+        return $r;
+    }
+    function mergeMask($a, $b) 
+    {
+        // default 
+        $ret = '';
+        for($i=0; $i< strlen($this->fullRights) ; $i++) {
+            if ((strpos($a, $this->fullRights[$i]) > -1) ||
+                (strpos($b, $this->fullRights[$i]) > -1)
+            ) {
+                $ret .= $this->fullRights[$i];
+            }
+        }
+        return $ret;
+        
+        
+    }
+    
+    
+    function defaultPermData()
+    {
+        
+        // we should do better caching of this... really..
+        
+        
+        
+        
+        // what they mean:
+        // A - add
+        // D - delete
+        // E - edit
+        // S - list
+        // P - print / export
+        // I - import
+        // M????
+        
+        
+        
+        static $Pman_DataObjects_Group_Right = array();
+        if (!empty($Pman_DataObjects_Group_Right)) {
+            return $Pman_DataObjects_Group_Right;
+        }
+        
+        $ff = HTML_FlexyFramework::get();
+        //print_R($ff);
+        $enabled =  array('Core') ;
+        $enabled = explode(',', $ff->enable);
+        $disabled =  explode(',', $ff->disable? $ff->disable: '');
+        $pman = dirname(__FILE__).'/../../';
+        $ret = array();
+         //echo '<PRE>';print_r($enabled);
+        foreach($enabled as $module) {
+            $fn = $pman. $module.  '/'.$module. '.perms.json';
+            if (!file_exists($fn)) {
+                continue;
+            }
+            $ar = (array)json_decode(file_get_contents($fn));
+           // echo '<PRE>';print_r($ar);
+            foreach($ar as $k=> $perm) {
+                if ($k[0] == '/') {
+                    continue; // it's a comment..
+                }
+                if (in_array($module, $disabled) || in_array($module.'.'. $k, $disabled)) {
+                    continue;
+                }
+                $ret[$module.'.'. $k ] = $perm;
+            }
+            
+        }
+        $Pman_DataObjects_Group_Right = $ret;
+       // print_r($ret);
+        return $Pman_DataObjects_Group_Right;
+         
+        
+    }
+    
+    function adminRights() // get the admin rights - used when no accounts are available..
+    {
+        $defs = $this->defaultPermData();
+        $ret = array();
+        foreach($defs as $k=>$v) {
+            $ret[$k] = $v[0];
+        
+        }
+        return $ret;
+        
+    }
+    
+    function validate()
+    {
+        // all groups must have the minimum privaligess..
+        // admin group must have all the privaliges
+        $g = DB_DataObject::Factory('Groups');
+        $g->get($this->group_id);
+        $defs = $this->defaultPermData();
+        switch($g->name) {
+            case "Administrators";
+                $this->AccessMask = $this->mergeMask($this->AccessMask, $defs[$this->rightname][0]);
+                break;
+                
+            default:
+                $this->AccessMask = $this->mergeMask($this->AccessMask, $defs[$this->rightname][1]);
+                break;
+        
+        }
+        
+    }
+    function genDefault()
+    {
+        // need to create to special groups, admin & DEFAULT.
+        $g = DB_DataObject::Factory('Groups');
+        //$g->name = 'Default';
+        //if (!$g->find(true)) {
+        //    $g->insert();
+        //}
+        $g->id = 0;
+        $this->applyDefs($g, 1);
+    
+        $g = DB_DataObject::Factory('Groups');
+        $g->name = 'Administrators';
+        if (!$g->find(true)) {
+            $g->insert();
+        }
+        $this->applyDefs($g, 0);
+        
+        
+    }
+        
+    function applyDefs($g, $usecol) {
+        
+        $defs = $this->defaultPermData();
+        //$usecol = 1;
+        foreach($defs as $rightname => $defdata) {
+            $gr = DB_DataObject::Factory('Group_Rights');
+            $gr->rightname  = $rightname;
+            $gr->group_id = $g->id;
+            if (!$gr->find(true)) {
+                $gr->AccessMask = $defdata[$usecol];
+                $gr->insert();
+                continue;
+            }
+            $oldgr = clone($gr);
+            $gr->AccessMask = $gr->mergeMask($gr->AccessMask, $defdata[$usecol]);
+            if ($gr->AccesMask == $oldgr->AccesMask) {
+                continue;
+            }
+            $gr->update($oldgr);
+        }
+        
+    }
+        
+    function checkPerm($lvl, $au) 
+    {
+        return false;
+    }  
+    
+}
diff --git a/DataObjects/Groups.php b/DataObjects/Groups.php
new file mode 100755 (executable)
index 0000000..1464b13
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Table Definition for Groups
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Groups extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Groups';                          // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $name;                            // string(64)  not_null
+    public $type;                            // int(11)  
+    public $leader;                          // int(11)  not_null
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    
+    // group types??
+    
+    function toEventString() {
+        return $this->name;
+    }
+    
+    function beforeDelete()
+    {
+        $x = DB_DataObject::factory('Groups');
+        $x->query("DELETE FROM Group_Rights WHERE group_id = {$this->id}");
+        $x->query("DELETE FROM Group_Members WHERE group_id = {$this->id}");
+    }
+    /**
+     * check who is trying to access this. false == access denied..
+     */
+    function checkPerm($lvl, $au) 
+    {
+        return $au->hasPerm("Core.".$this->tableName(), $lvl);    
+    } 
+    function onUpdate($old, $req, $roo)
+    {
+        $this->ensureLeaderMembership($roo);
+    }
+    function onInsert($req, $roo)
+    {
+        $this->ensureLeaderMembership($roo);
+    }
+    function ensureLeaderMembership($roo)
+    {
+        
+        // groups - make sure the leader is a member...
+        if (!$this->type || !$this->leader)
+        {
+            return true;
+        }
+        
+        $pi = DB_DataObject::factory('Person');
+        $pi->get($this->leader);
+            
+        $p = DB_DataObject::factory('Group_Members');
+        $p->group_id = $this->id;
+        $p->user_id = $this->leader;
+        //$p->type = 1; //???????
+        if (!$p->count()) {
+            
+            $p->insert();
+            $roo->addEvent("ADD", $p, $this->toEventString(). " Added " . $pi->toEventString());
+        }
+             
+    }
+    
+    function memberIds()
+    {
+        $gm = DB_Dataobject::factory('Group_Members');
+        $gm->group_id = $this->id;
+        return $gm->fetchAll('user_id');
+        
+    }
+    
+    function members()
+    {
+        
+        
+        $ids = $this->memberIds();
+        if (!$ids) {
+            return array();
+        }
+        $p = DB_Dataobject::factory('Person');
+        $p->whereAdd('id IN ('. implode(',', $ids) .')');
+        return $p->fetchAll();
+     
+        
+        
+    }
+    
+    
+}
diff --git a/DataObjects/I18n.php b/DataObjects/I18n.php
new file mode 100644 (file)
index 0000000..bd7a326
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Table Definition for i18n
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_I18n extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'i18n';                            // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $ltype;                           // string(1)  not_null multiple_key
+    public $lkey;                            // string(8)  not_null
+    public $inlang;                          // string(8)  not_null
+    public $lval;                            // string(64)  not_null
+
+     
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+}
diff --git a/DataObjects/Images.php b/DataObjects/Images.php
new file mode 100644 (file)
index 0000000..3a0cce0
--- /dev/null
@@ -0,0 +1,275 @@
+<?php
+/**
+ * Table Definition for Images
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Images extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Images';                          // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $filename;                        // string(255)  not_null
+    public $ontable;                         // string(32)  not_null multiple_key
+    public $onid;                            // int(11)  not_null
+    public $mimetype;                        // string(64)  not_null
+    public $width;                           // int(11)  not_null
+    public $height;                          // int(11)  not_null
+    public $filesize;                        // int(11)  not_null
+    public $displayorder;                    // int(11)  not_null
+    public $language;                        // string(6)  not_null
+    public $parent_image_id;                 // int(11)  not_null
+    public $created;                         // datetime(19)  not_null binary
+    public $imgtype;                         // string(32)  not_null
+    public $linkurl;                         // string(254)  not_null
+    public $descript;                        // blob(65535)  not_null blob
+    public $title;                           // string(128)  not_null
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    
+    function createFrom($file)
+    {
+        // copy the file into the storage area..
+        if (!file_exists($file) || !filesize($file)) {
+            return false;
+        }
+        
+        
+        $imgs = @getimagesize($file);
+        
+        if (empty($imgs) || empty($imgs[0]) || empty($imgs[1])) {
+            // it's a file!!!!
+        } else {
+            list($this->width , $this->height)  = $imgs;
+        }
+        
+        $this->filesize = filesize($file);
+        $this->created = date('Y-m-d H:i:s');
+        //DB_DataObject::debugLevel(1);
+        if (!$this->id) {
+            $this->insert();
+        } else {
+            $this->update();
+        }
+        
+        
+        
+        $f = $this->getStoreName();
+        $dest = dirname($f);
+        if (!file_exists($dest)) {
+            
+            $oldumask = umask(0);
+            mkdir($dest, 0770, true);
+            umask($oldumask);  
+        }
+        
+        copy($file,$f);
+        
+        // fill in details..
+        
+        /* thumbnails */
+        
+     
+       // $this->createThumbnail(0,50);
+        return true;
+        
+    }
+
+    /**
+     * Calculate target file name
+     *
+     * @return - target file name
+     */
+    function getStoreName() 
+    {
+        $opts = PEAR::getStaticProperty('Pman', 'options');
+        $fn = preg_replace('/[^a-z0-9\.]+/i', '_', $this->filename);
+        return implode( '/', array(
+            $opts['storedir'], '_images_', date('Y/m', strtotime($this->created)), $this->id . '-'. $fn
+        ));
+          
+    }
+
+     
+    /**
+     * deletes all the image instances of it...
+     * 
+     * 
+     */
+    function beforeDelete()
+    {
+        $fn = $this->getStoreName();
+        if (file_exists($fn)) {
+            unlink($fn);
+        }
+        
+        $b = basename($fn);
+        $d = dirname($fn);
+        $dh = opendir($d);
+        while (false !== ($fn = readdir($dh))) {
+            if (substr($fn, 0, strlen($b)) == $b) {
+                unlink($d. '/'. $fn);
+            }
+        }
+        
+        
+    }
+    
+  
+    /**
+     * onUpload (singlely attached image to a table)
+     */
+    
+    function onUploadWithTbl($tbl,  $fld)
+    {
+        if ( $tbl->__table == 'Images') {
+            return; // not upload to self...
+        }
+        if (empty($_FILES['imageUpload']['tmp_name']) || 
+            empty($_FILES['imageUpload']['name']) || 
+            empty($_FILES['imageUpload']['type'])
+        ) {
+            return false;
+        }
+        if ($tbl->$fld) {
+            $image = DB_DataObject::factory('Images');
+            $image->get($tbl->$fld);
+            $image->beforeDelete();
+            $image->delete();
+        }
+        
+        $image = DB_DataObject::factory('Images');
+        $image->onid = $tbl->id;
+        $image->ontable = $tbl->__table;
+        $image->filename = $_FILES['imageUpload']['name']; 
+        $image->mimetype = $_FILES['imageUpload']['type'];
+       
+        if (!$image->createFrom($_FILES['imageUpload']['tmp_name'])) {
+            return false;
+        }
+        $old = clone($tbl);
+        $tbl->$fld = $image->id;
+        $tbl->update($old);
+         
+    }
+    
+    // direct via roo...
+    function onUpload($ctrl)
+    {
+        
+        if (empty($_FILES['imageUpload']['tmp_name']) || 
+            empty($_FILES['imageUpload']['name']) || 
+            empty($_FILES['imageUpload']['type'])
+        ) {
+            $this->err = "Missing file details";
+            return false;
+        }
+        
+        if ($this->id) {
+            $this->beforeDelete();
+        }
+        if ( empty($this->ontable)) {
+            $this->err = "Missing  ontable";
+            return false;
+        }
+        
+        if (!empty($this->imgtype) && $this->imgtype[0] == '-' && !empty($this->onid)) {
+            // then its an upload 
+            $img  = DB_DataObject::factory('Images');
+            $img->onid = $this->onid;
+            $img->ontable = $this->ontable;
+            $img->imgtype = $this->imgtype;
+            
+            $img->find();
+            while ($img->fetch()) {
+                $img->beforeDelete();
+                $img->delete();
+            }
+            
+        }
+        
+        
+        
+        require_once 'File/MimeType.php';
+        $y = new File_MimeType();
+        $this->mimetype = $_FILES['imageUpload']['type'];
+        if (in_array($this->mimetype, array('text/application', 'application/octet-stream'))) { // weird tyeps..
+            $inf = pathinfo($_FILES['imageUpload']['name']);
+            $this->mimetype  = $y->fromExt($inf['extension']);
+        }
+        
+        
+        $ext = $y->toExt(trim((string) $this->mimetype ));
+        
+        $this->filename = empty($this->filename) ? 
+            $_FILES['imageUpload']['name'] : ($this->filename .'.'. $ext); 
+        
+        
+        
+        if (!$this->createFrom($_FILES['imageUpload']['tmp_name'])) {
+            return false;
+        }
+        return true;
+         
+    }
+     
+
+    function setFromRoo($ar, $roo)
+    {
+        // not sure why we do this.. 
+        
+        // if imgtype starts with '-' ? then we set the 'old' (probably to delete later)
+        if (!empty($ar['imgtype']) && !empty($ar['ontable']) && !empty($ar['onid']) && ($ar['imgtype'][0] == '-')) {
+            $this->setFrom($ar);
+            $this->limit(1);
+            if ($this->find(true)) {
+                $roo->old = clone($this);
+            }
+        }   
+            
+        
+        
+        
+         
+        
+        // FIXME - we should be checking perms here...
+        //if (method_exists($x, 'checkPerm') && !$x->checkPerm('E', $this->authUser))  {
+        //    $this->jerr("PERMISSION DENIED");
+        // }
+        // this should be doign update
+        $this->setFrom($ar);
+        
+        if (!isset($_FILES['imageUpload'])) {
+            return; // standard update...
+        }
+        
+        if ( !$this->onUpload($this)) {
+            $this->jerr("File upload failed");
+        }
+        $roo->addEvent("ADD", $this, $this->toEventString());
+        
+        $r = DB_DataObject::factory($this->tableName());
+        $r->id = $this->id;
+        $roo->loadMap($r);
+        $r->limit(1);
+        $r->find(true);
+        $roo->jok($r->toArray());
+         
+    }
+    function toEventString()
+    {
+        
+        //$p = DB_DataObject::factory($this->ontable);
+        //if (!is_$p) {
+        //    return "ERROR unknown table? {$this->ontable}";
+       // }
+        //$p->get($p->onid);
+        
+        return $this->filename .' - on ' . $this->ontable . ':' . $this->onid;
+        //$p->toEventString();
+    }
+ }
diff --git a/DataObjects/Office.php b/DataObjects/Office.php
new file mode 100644 (file)
index 0000000..935200f
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Table Definition for Office
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Office extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Office';                          // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $company_id;                      // int(11)  not_null
+    public $name;                            // string(64)  not_null
+    public $address;                         // blob(65535)  not_null blob
+    public $phone;                           // string(32)  not_null
+    public $fax;                             // string(32)  not_null
+    public $email;                           // string(128)  not_null
+    public $role;                            // string(32)  not_null
+
+     
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    function toEventString() {
+        return $this->name;
+    }
+    /**
+     * check who is trying to access this. false == access denied..
+     */
+    function checkPerm($lvl, $au) 
+    {
+        return $au->hasPerm("Core.Offices", $lvl);    
+    } 
+}
\ No newline at end of file
diff --git a/DataObjects/Person.php b/DataObjects/Person.php
new file mode 100644 (file)
index 0000000..87b1129
--- /dev/null
@@ -0,0 +1,496 @@
+<?php
+/**
+ * Table Definition for Person
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Person extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Person';                          // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $office_id;                       // int(11)  
+    public $name;                            // string(128)  not_null
+    public $phone;                           // string(32)  not_null
+    public $fax;                             // string(32)  not_null
+    public $email;                           // string(128)  not_null
+    public $company_id;                      // int(11)  
+    public $role;                            // string(32)  not_null
+    public $active;                          // int(11)  
+    public $remarks;                         // blob(65535)  not_null blob
+    public $passwd;                          // string(64)  not_null
+    public $owner_id;                        // int(11)  not_null
+    public $lang;                            // string(8)  
+    public $no_reset_sent;                   // int(11)  
+    public $project_id;                      // int(11)  
+    public $action_type;                     // string(32)  
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    
+    function sendTemplate($templateFile, $args)
+    {
+        
+        
+        
+        $content  = clone($this);
+        
+        foreach((array)$args as $k=>$v) {
+            $content->$k = $v;
+        }
+        
+        if (!in_array($templateFile, array(
+           // templates that can be sent without authentication.
+            'password_reset' ,
+            'password_welcome'
+            ))) {
+            $content->authUser = $this->getAuthUser();
+            if (!$content->authUser) {
+                return PEAR::raiseError("Not authenticated");
+            }
+        }
+        
+        $content->HTTP_HOST = $_SERVER["HTTP_HOST"];
+        /* use the regex compiler, as it doesnt parse <tags */
+        require_once 'HTML/Template/Flexy.php';
+        $template = new HTML_Template_Flexy( array(
+                 'compiler'    => 'Regex',
+                 'filters' => array('SimpleTags','Mail'),
+            //     'debug'=>1,
+            ));
+        
+     
+         
+        
+        $template->compile("mail/$templateFile.txt");
+        
+        /* use variables from this object to ouput data. */
+        $mailtext = $template->bufferedOutputObject($content);
+        //echo "<PRE>";print_R($mailtext);
+        
+        /* With the output try and send an email, using a few tricks in Mail_MimeDecode. */
+        require_once 'Mail/mimeDecode.php';
+        require_once 'Mail.php';
+        
+        $decoder = new Mail_mimeDecode($mailtext);
+        $parts = $decoder->getSendArray();
+        if (PEAR::isError($parts)) {
+            return $parts;
+            //echo "PROBLEM: {$parts->message}";
+            //exit;
+        } 
+        list($recipents,$headers,$body) = $parts;
+        $recipents = array($this->email);
+        if (!empty($content->bcc) && is_array($content->bcc)) {
+            $recipents =array_merge($recipents, $content->bcc);
+        }
+        //print_r($recipents);exit;
+        $mailOptions = PEAR::getStaticProperty('Mail','options');
+        $mail = Mail::factory("SMTP",$mailOptions);
+        $headers['Date'] = date('r');
+        if (PEAR::isError($mail)) {
+            return $mail;
+        } 
+        $oe = error_reporting(E_ALL ^ E_NOTICE);
+        $ret = $mail->send($recipents,$headers,$body);
+        error_reporting($oe);
+       
+        return $ret;
+    
+    }
+    function getEmailFrom()
+    {
+        return '"' . addslashes($this->name) . '" <' . $this->email . '>';
+    }
+    function toEventString() 
+    {
+        return empty($this->name) ? $this->email : $this->name;
+    } 
+    function whereAddIn($key, $list, $type) {
+        $ar = array();
+        foreach($list as $k) {
+            $ar[] = $type =='int' ? (int)$k : $this->escape($k);
+        }
+        if (!$ar) {
+            return;
+        }
+        $this->whereAdd("$key IN (". implode(',', $ar). ')');
+    }
+    function fetchAll($k= false, $v = false) 
+    {
+        // should it even do this!!!?!?
+        if ($k !== false && 
+                (   // only do this is we have not been explicit..
+                    empty($this->_query['data_select']) || 
+                    ($this->_query['data_select'] == '*')
+                )
+            ) {
+            $this->selectAdd();
+            $this->selectAdd($k);
+            if ($v !== false) {
+                $this->selectAdd($v);
+            }
+        }
+        
+        $this->find();
+        $ret = array();
+        while ($this->fetch()) {
+            if ($v !== false) {
+                $ret[$this->$k] = $this->$v;
+                continue;
+            }
+            $ret[] = $k === false ? clone($this) : $this->$k;
+        }
+        return $ret;
+         
+    }
+    //   ---------------- authentication / passwords and keys stuff  ----------------
+    function isAuth()
+    {
+        $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        @session_start();
+        if (!empty($_SESSION[__CLASS__][$sesPrefix .'-auth'])) {
+            // in session...
+            $a = unserialize($_SESSION[__CLASS__][$sesPrefix .'-auth']);
+            $u = DB_DataObject::factory('Person');
+            if ($u->get($a->id)) { //&& strlen($u->passwd)) {
+                return true;
+            }
+            $_SESSION[__CLASS__][$sesPrefix .'-auth'] = '';
+            
+        }
+        // not in session or not matched...
+        $u = DB_DataObject::factory('Person');
+        $u->whereAdd(' LENGTH(passwd) > 0');
+        $n = $u->count();
+        $error =  PEAR::getStaticProperty('DB_DataObject','lastError');
+        if ($error) {
+            die($error->toString()); // not really a good thing to do...
+        }
+        if (!$n){ // authenticated as there are no users in the system...
+            return true;
+        }
+        
+        return false;
+        
+    }
+    function getAuthUser()
+    {
+        if (!$this->isAuth()) {
+            return false;
+        }
+        $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        if (!empty($_SESSION[__CLASS__][$sesPrefix .'-auth'])) {
+            $a = unserialize($_SESSION[__CLASS__][$sesPrefix .'-auth']);
+            
+            $u = DB_DataObject::factory('Person');
+            if ($u->get($a->id)) { /// && strlen($u->passwd)) {
+                return clone($u);
+            }
+             
+        }
+        
+        $u = DB_DataObject::factory('Person');
+        $u->whereAdd(' LENGTH(passwd) > 0');
+        if (!$u->count()){
+            $u = DB_DataObject::factory('Person');
+            $u->id = -1;
+            return $u;
+            
+        }
+        return false;
+    }     
+    function login()
+    {
+        $this->isAuth(); // force session start..
+         $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        $_SESSION[__CLASS__][$sesPrefix .'-auth'] = serialize($this);
+        
+    }
+    function logout()
+    {
+        $this->isAuth(); // force session start..
+         $db = $this->getDatabaseConnection();
+        $sesPrefix = $db->dsn['database'];
+        $_SESSION[__CLASS__][$sesPrefix .'-auth'] = "";
+        
+    }    
+    function genPassKey ($t) 
+    {
+        return md5($this->email . $t. $this->passwd);
+    }
+    function simpleAuthKey($m = 0)
+    {
+        $month = $m > -1 ? date('Y-m') : date('Y-m', strtotime('LAST MONTH'));
+        
+        return md5(implode(',' ,  array($month, $this->email , $this->passwd, $this->id)));
+    } 
+    function checkPassword($val)
+    {
+        if (substr($this->passwd,0,1) == '$') {
+            return crypt($val,$this->passwd) == $this->passwd ;
+        }
+        // old style md5 passwords...- cant be used with courier....
+        return md5($val) == $this->passwd;
+    }
+    function setPassword($value) 
+    {
+        $salt='';
+        while(strlen($salt)<9) {
+            $salt.=chr(rand(64,126));
+            //php -r var_dump(crypt('testpassword', '$1$'. (rand(64,126)). '$'));
+        }
+        $this->passwd = crypt($value, '$1$'. $salt. '$');
+       
+    }      
+    
+    function company()
+    {
+        $x = DB_DataObject::factory('Companies');
+        $x->get($this->company_id);
+        return $x;
+    }
+    
+    //   ----------PERMS------  ----------------
+    function getPerms() 
+    {
+         //DB_DataObject::debugLevel(1);
+        // find out all the groups they are a member of.. + Default..
+        $g = DB_DataObject::Factory('Group_Rights');
+        if (!$g->count()) {
+            $g->genDefault();
+        }
+        if ($this->id < 0) {
+            return $g->adminRights();
+        }
+        
+        $g = DB_DataObject::Factory('Group_Members');
+        $grps = $g->listGroupMembership($this);
+        $isAdmin = $g->inAdmin;
+       // var_dump($grps);
+        // the load all the perms for those groups, and add them all together..
+        // then load all those 
+        $g = DB_DataObject::Factory('Group_Rights');
+        $ret =  $g->listPermsFromGroupIds($grps, $isAdmin);
+       // echo '<PRE>';print_r($ret);
+        return $ret;
+         
+        
+    }
+    function hasPerm($name, $lvl) 
+    {
+        static $pcache = array();
+        
+        if (!isset($pcache[$this->id])) {
+            $pcache[$this->id] = $this->getPerms();
+        }
+       // echo "<PRE>";print_r($pcache[$au->id]);
+       // var_dump($pcache[$au->id]);
+        if (empty($pcache[$this->id][$name])) {
+            return false;
+        }
+        
+        return strpos($pcache[$this->id][$name], $lvl) > -1;
+        
+    }    
+    
+    //  ------------ROO HOOKS------------------------------------
+    function applyFilters($q, $au)
+    {
+        if (!empty($q['query']['person_not_internal'])) {
+            $this->whereAdd(" join_company_id_id.isOwner = 0 ");
+        }
+        if (!empty($q['query']['person_internal_only_all'])) {
+            // must be internal and not current user (need for distribution list)
+            $this->whereAdd(" join_company_id_id.isOwner = 1");
+            
+        }
+        // -- for distribution
+        if (!empty($q['query']['person_internal_only'])) {
+            // must be internal and not current user (need for distribution list)
+            $this->whereAdd(" join_company_id_id.isOwner = 1");
+            
+            //$this->whereAdd(($this->tableName() == 'Person' ? 'Person' : "join_person_id_id") .
+            //    ".id  != ".$au->id);
+            $this->whereAdd("Person.id != {$au->id}");
+        } 
+        // staff list..
+        if (!empty($q['query']['person_inactive'])) {
+           // DB_Dataobject::debugLevel(1);
+            $this->active = 1;
+        }
+        
+        ///---------------- Group views --------
+        if (!empty($q['query']['in_group'])) {
+            // DB_DataObject::debugLevel(1);
+            $ing = (int) $q['query']['in_group'];
+            if ($q['query']['in_group'] == -1) {
+                // list all staff who are not in a group.
+                $this->whereAdd("Person.id NOT IN (
+                    SELECT distinct(user_id) FROM Group_Members LEFT JOIN
+                        Groups ON Groups.id = Group_Members.group_id
+                        WHERE Groups.type = ".$q['query']['type']."
+                    )");
+                
+                
+            } else {
+                
+                $this->whereAdd("Person.id IN (
+                    SELECT distinct(user_id) FROM Group_Members 
+                        WHERE group_id = $ing
+                    )");
+               }
+            
+        }
+        
+        if (!empty($q['query']['not_in_directory'])) { 
+            // it's a Person list..
+            // DB_DATaobjecT::debugLevel(1);
+            
+            // specific to project directory which is single comp. login
+            //
+            $owncomp = DB_DataObject::Factory('Companies');
+            $owncomp->get('comptype', 'OWNER');
+            if ($q['company_id'] == $owncomp->id) {
+                $this->active =1;
+            }
+            
+            
+            if ( $q['query']['not_in_directory'] > -1) {
+                // can list current - so that it does not break!!!
+                $x->whereAdd('Person.id NOT IN 
+                    ( SELECT distinct person_id FROM ProjectDirectory WHERE
+                        project_id = ' . $q['query']['not_in_directory'] . ' AND 
+                        company_id = ' . $this->company_id . ')');
+            }
+        }
+        
+        if (!empty($q['query']['search'])) {
+            $s = $this->escape($q['query']['search']);
+                    $this->whereAdd("
+                        Person.name LIKE '%$s%'  OR
+                        Person.email LIKE '%$s%'  OR
+                        Person.role LIKE '%$s%'  OR
+                        Person.remarks LIKE '%$s%' 
+                        
+                    ");
+        }
+        
+        //
+    }
+    function setFromRoo($ar, $roo)
+    {
+        $this->setFrom($ar);
+        if (!empty($ar['passwd1'])) {
+            $this->setPassword($ar['passwd1']);
+        }
+        
+        
+        if (    $this->id &&
+                ($this->email == $roo->old->email)&&
+                ($this->company_id == $roo->old->company_id)
+            ) {
+            return true;
+        }
+        $xx = DB_Dataobject::factory('Person');
+        $xx->setFrom(array(
+            'email' => $this->email,
+           // 'company_id' => $x->company_id
+        ));
+        
+        if ($xx->count()) {
+            return "Duplicate Email found";
+        }
+        return true;
+    }    
+    function checkPerm($lvl, $au, $changes=false) //heck who is trying to access this. false == access denied..
+    {
+         // determine if it's staff!!!
+         
+         
+        if ($au->company()->comptype != 'OWNER') {
+            
+            // - can not change company!!!
+            if ($changes && 
+                isset($changes['company_id']) && 
+                $changes['company_id'] != $au->company_id) {
+                return false;
+            }
+            // can only set new emails..
+            if ($changes && 
+                    !empty($this->email) && 
+                    isset($changes['email']) && 
+                    $changes['email'] != $this->email) {
+                return false;
+            }
+            
+            // edit self... - what about other staff members...
+            
+            return $this->company_id == $au->company_id;
+        }
+         
+         
+        // yes, only owner company can mess with this...
+        $owncomp = DB_DataObject::Factory('Companies');
+        $owncomp->get('comptype', 'OWNER');
+        
+        $isStaff = ($this->company_id ==  $owncomp->id);
+        
+    
+        switch ($lvl) {
+            // extra case change passwod?
+            case 'P': //??? password
+                // standard perms -- for editing + if the user is dowing them selves..
+                $ret = $isStaff ? $au->hasPerm("Core.Person", "E") : $au->hasPerm("Core.Staff", "E");
+                return $ret || $au->id == $this->id;
+            
+            case 'S': // list..
+                return $au->hasPerm("Core.Person", "S");
+            
+            case 'E': // edit
+                return $isStaff ? $au->hasPerm("Core.Person", "E") : $au->hasPerm("Core.Staff", "E");
+            
+            case 'A': // add
+                return $isStaff ? $au->hasPerm("Core.Person", "A") : $au->hasPerm("Core.Staff", "A");
+            
+            case 'D': // add
+                return $isStaff ? $au->hasPerm("Core.Person", "D") : $au->hasPerm("Core.Staff", "D");
+        
+        }
+        return false;
+    }
+    function onInsert($req, $roo)  
+    {
+        
+        if ($roo->authUser->id < 0) {
+            $g = DB_DataObject::factory('Groups');
+            $g->type = 0;
+            $g->get('name', 'Administrators');
+            
+            $p = DB_DataObject::factory('Group_Members');
+            $p->group_id = $g->id;
+            $p->user_id = $this->id;     
+            if (!$p->count()) {
+                $p->insert();
+                $roo->addEvent("ADD", $p, $g->toEventString(). " Added " . $this->toEventString());
+            }
+            $this->login();
+        }
+        if (!empty($req['project_id_addto'])) {
+            $pd = DB_DataObject::factory('ProjectDirectory');
+            $pd->project_id = $req['project_id_addto'];
+            $pd->person_id = $this->id; 
+            $pd->ispm =0;
+            $pd->office_id = $this->office_id;
+            $pd->company_id = $this->company_id;
+            $pd->insert();
+        }
+        
+    }
+ }
diff --git a/DataObjects/Proftp_groups.php b/DataObjects/Proftp_groups.php
new file mode 100644 (file)
index 0000000..c18c899
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Table Definition for proftp_groups
+ * 
+ * -- this is needed for proftp integratin, but it's not used.. AFAIK
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Proftp_groups extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'proftp_groups';                   // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $grpid;                           // int(11)  not_null multiple_key
+    public $grpname;                         // string(32)  not_null
+    public $grpmembers;                      // blob(65535)  blob
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+}
diff --git a/DataObjects/Projects.php b/DataObjects/Projects.php
new file mode 100644 (file)
index 0000000..ef319f2
--- /dev/null
@@ -0,0 +1,348 @@
+<?php
+/**
+ * Table Definition for Projects
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Projects extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'Projects';                        // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $name;                            // string(254)  not_null
+    public $remarks;                         // blob(65535)  not_null blob
+    public $owner_id;                        // int(11)  
+    public $code;                            // string(32)  not_null multiple_key
+    public $active;                          // int(11)  
+    public $type;                            // string(1)  not_null
+    public $client_id;                       // int(11)  not_null
+    public $team_id;                         // int(11)  not_null
+    public $file_location;                   // string(254)  not_null
+    public $open_date;                       // date(10)  binary
+    public $open_by;                         // int(11)  not_null
+    public $countries;                       // string(128)  not_null
+    public $languages;                       // string(128)  not_null
+    public $close_date;                      // date(10)  binary
+    public $agency_id;                       // int(11)  not_null
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+    function getProjectManagers()
+    {
+        $c = DB_DataObject::factory('Companies');
+        $c->isOwner = 1;
+        if (!$c->find(true)) {
+            return array();
+        }
+        
+        
+        $pmids = array();
+        $pd = DB_DataObject::factory('ProjectDirectory');
+        $pd->project_id = $this->id;
+        $pd->company_id = $c->id;
+        $pd->ispm = 1;
+        if (!$pd->count()) {
+            return array();
+        }
+        $pd->selectAdd();
+        $pd->selectAdd('distinct (person_id)');
+        
+        $pd->find();
+        while ($pd->fetch()) {
+            $pmids[] = $pd->person_id;
+            
+        }
+        $ret = array();
+        $p =  DB_DataObject::factory('Person');
+        $p->whereAdd('id IN ('. implode(',', $pmids) .')');
+        $p->find();
+        while ($p->fetch()) {
+            $ret[] = clone($p);
+        }
+        return $ret;
+        
+    }
+
+    function toEventString() {
+        return $this->name;
+    }
+    
+    /**
+     * apply filter arguemnts
+     * @param $query - see below
+     * @param $authUser  - authenticated user
+     * 
+     * Query specs:
+     *   [query]
+     *       project_search = text string.
+     *       project_indaterange - a/c/o 
+     *       project_filter = ALL || P,N,U ....
+     * 
+     * // to get a users valid project list - just use array('query' => array('project_filter'=> 'ALL'));
+     * 
+     */
+    
+    function applyFilters($q, $au)
+    {
+         
+        if (!empty($q['query']['project_search'])) {
+            $s = $this->escape($q['query']['project_search']);
+            $this->whereAdd(" (Projects.code LIKE '$s%') OR (Projects.name LIKE '%$s%')");
+        }
+        // types of project to list ... - default is only the open ones...
+        if (!empty($q['query']['project_indaterange'])) {
+            switch($q['query']['project_indaterange']) {
+                case 'A': // all
+                    break; 
+                case 'C': // current
+                     $this->whereAdd('Projects.close_date >= NOW()');
+                    break;
+                case 'O': // old
+                    $this->whereAdd('Projects.close_date < NOW()');
+                    break;
+               }
+        }
+        
+        if (empty($q['query']['project_filter'])  || $q['query']['project_filter'] != 'ALL') {
+            
+               
+            $pf = empty($q['query']['project_filter']) ? 'P,N,U' : $q['query']['project_filter'];
+            $bits= explode(',' ,$pf);
+            foreach($bits as $i=>$k) {
+                $bits[$i] = $this->escape($k);
+            }
+            $this->whereAdd("Projects.type in ('". implode("','", $bits) . "')");
+        }
+         // user projects!!!! - make sure they can only see project they are suppsed to..
+         // only applies to document stuff..
+          
+        if (!$au->hasPerm('Core.Projects_All','S') &&
+            $au->hasPerm('Documents.Documents','S')) {
+            
+            
+            
+            $pr = DB_DataObject::factory('Projects');
+            $pr->whereAdd("Projects.type IN ('N','X')");
+            $prjs = $pr->fetchAll('id');
+            
+            
+            $pd = DB_DataObject::factory('ProjectDirectory');
+            $pd->joinAdd(DB_DataObject::factory('Projects'), 'LEFT');
+            $pd->whereAdd("Projects.type NOT IN ('N','X')");
+            $pd->person_id = $au->id;
+            
+            $prjs = array_merge($prjs, $pd->fetchAll('project_id'));
+            if (count($prjs)) {
+                $this->whereAdd("
+                     (Projects.id IN (".implode(',', $prjs).")) 
+                ");
+            }  else {
+                $this->whereAdd("1=0"); // can see nothing!!!
+            }
+        }
+        // this is clipping related..  -- we should have an API for addons like this.. (and docs)
+        
+        if ($au->company()->comptype == 'SUPPLIER') {
+            $pr = DB_DataObject::factory('CampaignAssign');
+            $pr->supplier_id = $au->company_id;
+            $prjs = $pr->fetchAll('project_id');
+             if (count($prjs)) {
+                $this->whereAdd("
+                     (Projects.id IN (".implode(',', $prjs).")) 
+                ");
+            }  else {
+                $this->whereAdd("1=0"); // can see nothing!!!
+            }
+        }
+        if ($au->company()->comptype == 'CLIENT') {
+            $this->client_id = $au->company()->id; // can see nothing!!!
+            
+        }
+                 
+        
+        
+        
+    }
+    function whereAddIn($key, $list, $type) {
+        $ar = array();
+        foreach($list as $k) {
+            $ar[] = $type =='int' ? (int)$k : $this->escape($k);
+        }
+        if (!$ar) {
+            return;
+        }
+        $this->whereAdd("$key IN (". implode(',', $ar). ')');
+    }
+    function onInsert()
+    {
+        $oo = clone($this);
+        if (empty($this->code)) {
+            $this->code = 'C' + $this->client_id + '-P' + $this->id;
+            $this->update($oo);
+        }
+    }
+    
+    function onUpdate($old)
+    {
+        $oo = clone($this);
+        if (empty($this->code)) {
+            $this->code = 'C' + $this->client_id + '-P' + $this->id;
+            $this->update($oo);
+        }
+        
+        if ($old->code == $this->code) {
+            return;
+        }
+        
+        
+        $opts = PEAR::getStaticProperty('Pman', 'options');
+        
+        $olddir =  $opts['storedir'] . '/' . $old->code;
+        $newdir =  $opts['storedir'] . '/' . $this->code;
+        if ( file_exists($olddir)) {
+            move ($olddir, $newdir);
+        }
+         
+        
+    }
+    
+    function prune()
+    {
+        if (!$this->prune) { // non-expiring..
+            return;
+        }
+        
+        $d = DB_DataObject::factory('Document');
+        $d->whereAdd("date_rec < NOW - INTERVAL {$this->expires} DAYS"); 
+        $d->find();
+        while ($d->fetch()) {
+            $d->prune();
+        }
+        
+        
+        
+        
+        
+        
+        
+    }
+    /**
+     * our camp interface uses the format Cxxx-Pyyyyyy to refer to the project.
+     */
+    function getByCodeRef($str)
+    {
+        $bits = explode('-', $str);
+        if ((count($bits) != 2) || $bits[0][0] != 'C' ||  $bits[1][0] != 'P' ) {
+            return false;
+        }
+        $comp = substr($bits[0], 1);
+        $id = (int) substr($bits[1], 1);
+        return $id && $this->get($id);
+        
+    }
+    
+    
+    function i18toArray($type, $str) 
+    {
+        if (empty($str)) {
+            return array();
+        }
+        static $au;
+        static $langs;
+        static $cts;
+        
+        if (!$au) {
+            $u = DB_DataObject::factory('Person');
+            $au =$u->getAuthUser();
+            $lang = empty($au->lang ) ? 'en' : $au->lang;
+            $lbits = explode('_', strtoupper($lang));
+            // no validation here!!!!
+            require_once 'I18Nv2/Language.php';
+            require_once 'I18Nv2/Country.php';
+            $langs = new I18Nv2_Language($lbits[0]); // locale support not there??
+            $cts = new I18Nv2_Country($lbits[0]); // lo
+            
+        }
+        $lk = $type == 'c' ? $cts : $langs;
+        $ar  =explode(',', $str);
+        $ret = array();
+        foreach($ar as $k) {
+            $ret[] = array('code'=>$k, 'title' => $lk->getName($k));
+        }
+        return $ret;
+        // work out locale...
+        
+        
+        
+        
+    }
+    
+    
+    function toRooArray($f='%s') {
+        $ret = parent::toArray($f);
+        // sor tout 
+        $ret['countrylist'] = $this->I18toArray('c',$ret['countries']);
+        $ret['languagelist'] = $this->I18toArray('l',$ret['languages']);
+        return $ret;
+    }
+    function setFromRoo($q) 
+    {
+        $this->setFrom($q);
+        if (isset($q['open_date'])) {
+            $this->open_date = date('Y-m-d', strtotime(
+                implode('-', array_reverse(explode('/', $q['open_date'])))
+            ));
+        }
+        return true;
+    }
+    
+    function fetchAll($k= false) {
+        if ($k !== false) {
+            $this->selectAdd();
+            $this->selectAdd($k);
+        }
+        
+        $this->find();
+        $ret = array();
+        while ($this->fetch()) {
+            $ret[] = $k === false ? clone($this) : $this->$k;
+        }
+        return $ret;
+         
+    }
+    
+    /**
+     * fetch a list of user projects.
+     * if you need to filter open/closed.. then add whereAdds before calling
+     */
+    function getUserProjects($au, $data='id') // COMPANY BASED!!!!
+    {
+        $id = (int) $au->company_id;
+        $this->whereAdd("
+            (client_id= $id) OR (agency_id= $id)
+        ");
+        if (!empty($data)) {
+            $this->selectAdd();
+            $this->selectAdd($data);
+        }
+        $this->find();
+        $ret = array();
+        while ($this->fetch()) {
+            $ret[] = empty($data) ? clone($this) : $this->$data;
+        }
+        return $ret;
+            
+    }
+    
+    
+    /**
+     * check who is trying to access this. false == access denied..
+     */
+    function checkPerm($lvl, $au) 
+    {
+        return $au->hasPerm("Core.Projects_Member_Of",$lvl) || $au->hasPerm("Core.Projects_All",$lvl);
+    }
+}
diff --git a/DataObjects/Translations.php b/DataObjects/Translations.php
new file mode 100644 (file)
index 0000000..a3d5718
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Table Definition for translations
+ */
+require_once 'DB/DataObject.php';
+
+class Pman_Core_DataObjects_Translations extends DB_DataObject 
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'translations';                    // table name
+    public $id;                              // int(11)  not_null primary_key auto_increment
+    public $module;                          // string(64)  not_null multiple_key
+    public $tfile;                           // string(128)  not_null
+    public $tlang;                           // string(8)  not_null
+    public $tkey;                            // string(32)  not_null
+    public $tval;                            // blob(-1)  not_null blob
+
+    
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+}
diff --git a/DataObjects/core.sql b/DataObjects/core.sql
new file mode 100644 (file)
index 0000000..5faa9f9
--- /dev/null
@@ -0,0 +1,283 @@
+
+CREATE TABLE `Companies` (
+  `code` varchar(32) collate utf8_unicode_ci NOT NULL,
+  `name` varchar(128) collate utf8_unicode_ci default NULL,
+  `remarks` text collate utf8_unicode_ci,
+  `owner_id` int(11) NOT NULL,
+  `address` text collate utf8_unicode_ci,
+  `tel` varchar(32) collate utf8_unicode_ci default NULL,
+  `fax` varchar(32) collate utf8_unicode_ci default NULL,
+  `email` varchar(128) collate utf8_unicode_ci default NULL,
+  `id` int(11) NOT NULL auto_increment,
+  `isOwner` int(11) default NULL,
+  PRIMARY KEY  USING BTREE (`id`),
+  KEY `Company_Name` (`name`)
+) ;
+
+alter table Companies change column isOwner isOwner int(11);
+ALTER TABLE Companies ADD COLUMN logo_id INT(11)  NOT NULL;
+ALTER TABLE Companies  ADD COLUMN background_color varchar(8)  NOT NULL;
+ALTER TABLE Companies  ADD COLUMN comptype varchar(8)  NOT NULL;
+
+
+ALTER TABLE `Companies` ADD COLUMN `url` varchar(254)  NOT NULL;
+ALTER TABLE `Companies` ADD COLUMN `main_office_id` int(11)  NOT NULL;
+
+
+ALTER TABLE `Companies` ADD COLUMN `created_by` int(11)  NOT NULL;
+ALTER TABLE `Companies` ADD COLUMN `created_dt` datetime  NOT NULL;
+ALTER TABLE `Companies` ADD COLUMN `updated_by` int(11)  NOT NULL;
+ALTER TABLE `Companies` ADD COLUMN `updated_dt` datetime  NOT NULL;
+
+ALTER TABLE `Companies` ADD COLUMN   `passwd` varchar(64) NOT NULL;
+
+UPDATE Companies set comptype='OWNER' where isOwner=1;
+
+
+
+CREATE TABLE `Events` (
+  `id` int(11) NOT NULL auto_increment,
+  `person_name` varchar(128) collate utf8_unicode_ci default NULL,
+  `event_when` datetime default NULL,
+  `action` varchar(32) collate utf8_unicode_ci default NULL,
+  `ipaddr` varchar(16) collate utf8_unicode_ci default NULL,
+  `on_id` int(11) default NULL,
+  `on_table` varchar(64) collate utf8_unicode_ci default NULL,
+  `person_id` int(11) default NULL,
+  `remarks` text collate utf8_unicode_ci,
+  PRIMARY KEY  (`id`)
+) ;
+
+
+ALTER TABLE Events CHANGE COLUMN EventID id INT(11) AUTO_INCREMENT NOT NULL;
+ALTER TABLE Events CHANGE COLUMN User person_name VARCHAR(128);
+ALTER TABLE Events ADD COLUMN person_id INT(11);
+ALTER TABLE Events CHANGE COLUMN Date event_when DATETIME;
+ALTER TABLE Events CHANGE COLUMN Event action VARCHAR(32);
+ALTER TABLE Events CHANGE COLUMN Host ipaddr VARCHAR(16);
+ALTER TABLE Events CHANGE COLUMN ItemID on_id INT(11);
+ALTER TABLE Events CHANGE COLUMN Container on_table VARCHAR(64);
+ALTER TABLE Events ADD COLUMN remarks INT(11);
+
+
+
+CREATE TABLE `Group_Members` (
+  `group_id` int(11) default NULL,
+  `id` int(11) NOT NULL auto_increment,
+  `user_id` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`id`)
+);
+
+
+CREATE TABLE `Group_Rights` (
+  `rightname` varchar(64) collate utf8_unicode_ci NOT NULL,
+  `group_id` int(11) NOT NULL,
+  `AccessMask` varchar(10) collate utf8_unicode_ci NOT NULL,
+  `id` int(11) NOT NULL auto_increment,
+  PRIMARY KEY  (`id`)
+) ;
+
+
+
+
+CREATE TABLE `Groups` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) collate utf8_unicode_ci NOT NULL,
+  `type` int(11) default NULL,
+  `leader` int(11) NOT NULL default '0',
+  PRIMARY KEY  USING BTREE (`id`)
+);
+
+
+
+alter table Groups add column type int(11) default 0;
+ALTER TABLE `Groups` ADD COLUMN `leader` int(11)  NOT NULL default 0;
+ALTER TABLE Groups CHANGE COLUMN type type int(11) default 0;
+
+
+
+
+CREATE TABLE `Office` (
+  `id` int(11) NOT NULL auto_increment,
+  `company_id` int(11) NOT NULL default '0',
+  `name` varchar(64) character set latin1 NOT NULL,
+  `address` text character set latin1 NOT NULL,
+  `phone` varchar(32) character set latin1 NOT NULL,
+  `fax` varchar(32) character set latin1 NOT NULL,
+  `email` varchar(128) character set latin1 NOT NULL,
+  `role` varchar(32) character set latin1 NOT NULL,
+  PRIMARY KEY  (`id`)
+);
+
+CREATE TABLE `Person` (
+  `id` int(11) NOT NULL auto_increment,
+  `office_id` int(11) default '0',
+  `name` varchar(128) character set latin1 NOT NULL,
+  `phone` varchar(32) character set latin1 NOT NULL,
+  `fax` varchar(32) character set latin1 NOT NULL,
+  `email` varchar(128) character set latin1 NOT NULL,
+  `company_id` int(11) default '0',
+  `role` varchar(32) character set latin1 NOT NULL,
+  `active` int(11) default NULL,
+  `remarks` text NOT NULL,
+  `passwd` varchar(64) NOT NULL,
+  `owner_id` int(11) NOT NULL,
+  `lang` varchar(8) default 'en',
+  `no_reset_sent` int(11) default '0',
+  PRIMARY KEY  (`id`)
+) ;
+
+
+ALTER TABLE Person ADD COLUMN no_reset_sent INT(11) DEFAULT 0;
+ALTER TABLE Person ADD COLUMN action_type VARCHAR(32) DEFAULT '';
+ALTER TABLE Person CHANGE COLUMN active active int(11);
+ALTER TABLE Person ADD COLUMN project_id int(11) default 0;
+
+ALTER TABLE Person ADD COLUMN action_type VARCHAR(32) default '';
+
+
+
+
+CREATE TABLE `ProjectDirectory` (
+  `id` int(11) NOT NULL auto_increment,
+  `project_id` int(11) NOT NULL,
+  `person_id` int(11) NOT NULL,
+  `ispm` int(11) NOT NULL,
+  `office_id` int(11) default NULL,
+  `company_id` int(11) default NULL,
+  `role` varchar(16) NOT NULL,
+  PRIMARY KEY  (`id`)
+) ;
+CREATE TABLE `Projects` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(254) collate utf8_unicode_ci NOT NULL,
+  `remarks` text collate utf8_unicode_ci NOT NULL,
+  `owner_id` int(11) default NULL,
+  `code` varchar(32) collate utf8_unicode_ci NOT NULL,
+  `active` int(11) default '1',
+  `type` varchar(1) collate utf8_unicode_ci NOT NULL default 'P',
+  `client_id` int(11) NOT NULL default '0',
+  `team_id` int(11) NOT NULL default '0',
+  `file_location` varchar(254) collate utf8_unicode_ci NOT NULL default '',
+  `open_date` date default NULL,
+  `open_by` int(11) NOT NULL default '0',
+  PRIMARY KEY  USING BTREE (`id`),
+  KEY `plookup` (`code`)
+) ;
+ alter table Projects add column active int(11) default 1;
+alter table Projects add index plookup(code);
+
+ALTER TABLE  Projects  ADD COLUMN `type` varchar(1)  NOT NULL DEFAULT 'P';
+ ALTER TABLE  Projects ADD COLUMN `client_id` int(11)  NOT NULL DEFAULT 0 ;
+ ALTER TABLE  Projects ADD COLUMN `team_id` int(11)  NOT NULL DEFAULT 0;
+ ALTER TABLE  Projects ADD COLUMN `file_location` varchar(254)  NOT NULL DEFAULT '';
+ ALTER TABLE  Projects ADD COLUMN `open_date` date  ;
+ ALTER TABLE  Projects ADD COLUMN `close_date` date  ;
+ ALTER TABLE  Projects ADD COLUMN `open_by` int(11)  NOT NULL DEFAULT 0;
+
+ALTER TABLE `Projects` ADD COLUMN `countries` varchar(128)  NOT NULL;
+ALTER TABLE `Projects`  ADD COLUMN `languages` varchar(128)  NOT NULL;
+
+ALTER TABLE  Projects ADD COLUMN agency_id int(11)  NOT NULL DEFAULT 0 ;
+
+
+CREATE TABLE `Remarks` (
+  `id` int(11) NOT NULL auto_increment,
+  `remark` text NOT NULL,
+  `add_when` datetime NOT NULL,
+  `on_table` varchar(32) NOT NULL,
+  `on_id` int(11) NOT NULL,
+  `person_name` varchar(64) NOT NULL,
+  `person_id` int(11) NOT NULL,
+  `isHTML` int(11) default '0',
+  `action` varchar(32) default '',
+  PRIMARY KEY  (`id`),
+  KEY `qlookup` (`add_when`,`on_table`,`on_id`)
+);
+ alter table Remarks add column isHTML int(11) default 0;
+
+
+
+CREATE TABLE   `Images` (
+  `id` int(11) NOT NULL auto_increment,
+  `filename` varchar(255) NOT NULL default '',
+  `ontable` varchar(32) NOT NULL default '',
+  `onid` int(11) NOT NULL default '0',
+  `mimetype` varchar(64) NOT NULL default '',
+  `width` int(11) NOT NULL default '0',
+  `height` int(11) NOT NULL default '0',
+  `filesize` int(11) NOT NULL default '0',
+  `displayorder` int(11) NOT NULL default '0',
+  `language` varchar(6) NOT NULL default 'en',
+  `parent_image_id` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`id`)
+);
+
+
+
+
+
+
+
+ALTER TABLE `Images` ADD INDEX `lookup`(`ontable`, `onid`);
+
+ALTER TABLE `Images` ADD COLUMN `created` datetime  NOT NULL;
+ALTER TABLE  `Images` ADD COLUMN `imgtype` VARCHAR(32) DEFAULT '' NOT NULL;
+ALTER TABLE  `Images` ADD COLUMN `linkurl` VARCHAR(254) DEFAULT '' NOT NULL;
+ALTER TABLE  `Images` ADD COLUMN `descript` TEXT DEFAULT '' NOT NULL;
+ALTER TABLE  `Images` ADD COLUMN `title` VARCHAR(128) DEFAULT '' NOT NULL;
+
+
+
+
+
+
+
+CREATE TABLE  `i18n` (
+  `id` int(11)  NOT NULL AUTO_INCREMENT,
+  `ltype` varchar(1)  NOT NULL,
+  `lkey` varchar(8)  NOT NULL,
+  `inlang` varchar(8)  NOT NULL,
+  `lval` varchar(64)  NOT NULL,
+  PRIMARY KEY (`id`),
+  INDEX `lookup`(`ltype`, `lkey`, `inlang`)
+) ;
+
+
+DROP FUNCTION IF EXISTS i18n_translate;
+
+DELIMITER $$
+CREATE FUNCTION i18n_translate(in_ltype  varchar(1) , in_lkey varchar(8), in_inlang varchar(8)) 
+        RETURNS VARCHAR(64) DETERMINISTIC
+    BEGIN
+        DECLARE ret  VARCHAR(64);
+        SET ret  = '';
+        SELECT lval INTO ret FROM i18n
+            WHERE ltype=in_ltype AND lkey=in_lkey and inlang=in_inlang LIMIT 1;
+        RETURN ret;
+        
+    END $$
+DELIMITER ;
+                       
+        
+    
+CREATE TABLE `Signup` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(128) character set latin1 NOT NULL,
+  `email` varchar(128) character set latin1 NOT NULL,
+  `role` varchar(32) character set latin1 NOT NULL,
+  `company_name` varchar(128) character set latin1 NOT NULL,
+  `person_id` int(11) default 0,
+  `remarks` text NOT NULL,
+  
+  PRIMARY KEY  (`id`)
+) ;
+
\ No newline at end of file
diff --git a/DataObjects/pman.ini b/DataObjects/pman.ini
new file mode 100644 (file)
index 0000000..69d2c79
--- /dev/null
@@ -0,0 +1,172 @@
+
+[Companies]
+code = 130
+name = 2
+remarks = 66
+owner_id = 129
+address = 66
+tel = 2
+fax = 2
+email = 2
+id = 129
+isOwner = 1
+logo_id = 129
+background_color = 130
+comptype = 130
+ava_craft = 2
+url = 130
+main_office_id = 129
+created_by = 129
+created_dt = 142
+updated_by = 129
+updated_dt = 142
+passwd = 130
+
+[Companies__keys]
+id = N
+
+[Events]
+id = 129
+person_name = 2
+event_when = 14
+action = 2
+ipaddr = 2
+on_id = 1
+on_table = 2
+person_id = 1
+remarks = 66
+
+[Events__keys]
+id = N
+
+[Group_Members]
+group_id = 1
+id = 129
+user_id = 129
+
+[Group_Members__keys]
+id = N
+
+[Group_Rights]
+rightname = 130
+group_id = 129
+AccessMask = 130
+id = 129
+
+[Group_Rights__keys]
+id = N
+
+[Groups]
+id = 129
+name = 130
+type = 1
+leader = 129
+
+[Groups__keys]
+id = N
+
+[Images]
+id = 129
+filename = 130
+ontable = 130
+onid = 129
+mimetype = 130
+width = 129
+height = 129
+filesize = 129
+displayorder = 129
+language = 130
+parent_image_id = 129
+created = 142
+imgtype = 130
+linkurl = 130
+descript = 194
+title = 130
+
+[Images__keys]
+id = N
+
+[Office]
+id = 129
+company_id = 129
+name = 130
+address = 194
+phone = 130
+fax = 130
+email = 130
+role = 130
+
+[Office__keys]
+id = N
+
+[Person]
+id = 129
+office_id = 1
+name = 130
+phone = 130
+fax = 130
+email = 130
+company_id = 1
+role = 130
+active = 1
+remarks = 194
+passwd = 130
+owner_id = 129
+lang = 2
+no_reset_sent = 1
+project_id = 1
+action_type = 2
+
+[Person__keys]
+id = N
+
+[Projects]
+id = 129
+name = 130
+remarks = 194
+owner_id = 1
+code = 130
+active = 1
+type = 130
+client_id = 129
+team_id = 129
+file_location = 130
+open_date = 6
+open_by = 129
+countries = 130
+languages = 130
+close_date = 6
+agency_id = 129
+
+[Projects__keys]
+id = N
+
+[i18n]
+id = 129
+ltype = 130
+lkey = 130
+inlang = 130
+lval = 130
+
+[i18n__keys]
+id = N
+
+[proftp_groups]
+id = 129
+grpid = 129
+grpname = 130
+grpmembers = 66
+
+[proftp_groups__keys]
+id = N
+
+[translations]
+id = 129
+module = 130
+tfile = 130
+tlang = 130
+tkey = 130
+tval = 194
+
+[translations__keys]
+id = N
diff --git a/DataObjects/pman.links.ini b/DataObjects/pman.links.ini
new file mode 100644 (file)
index 0000000..2258fd8
--- /dev/null
@@ -0,0 +1,54 @@
+
+[Images]
+parent_image_id = Images:id
+
+[Person]
+office_id = Office:id
+company_id = Companies:id
+project_id = Projects:id
+owner_id = Person:id
+
+[Companies]
+logo_id = Images:id
+owner_id = Person:id
+main_office_id = Office:id
+
+[Office]
+company_id = Companies:id
+
+[Projects]
+client_id = Companies:id
+agency_id = Companies:id
+team_id = Groups:id
+open_by = Person:id
+owner_id = Person:id
+
+[Groups]
+leader = Person:id
+
+[Group_Members]
+group_id = Groups:id
+user_id =  Person:id
+
+[Group_Rights]
+group_id = Groups:id
+
+[Events]
+person_id = Person:id
+
+
+
+
+[database__render]
+Projects = name
+Companies = name
+Office =  name
+Person = name
+Groups = name
+Images = filename
+
+  
+
diff --git a/GroupMembers.php b/GroupMembers.php
new file mode 100644 (file)
index 0000000..576961d
--- /dev/null
@@ -0,0 +1,183 @@
+<?php
+
+// neeeds fixing!!!
+/**
+ * 
+ * Part of core!
+ * 
+ */
+
+require_once 'Pman.php';
+
+class Pman_Core_GroupMembers extends Pman
+{
+    function getAuth() {
+        parent::getAuth(); // load company!
+        $au = $this->getAuthUser();
+        if (!$au) {
+            $this->jerr("Not authenticated", array('authFailure' => true));
+        }
+        if ($au->company()->comptype != 'OWNER') {
+            $this->jerr("Permission Denied" );
+        }
+        $this->authUser = $au;
+        return true;
+    }
+    
+     
+    function get()
+    {
+        // must recieve a group..
+        if (empty($_GET['group_id']) || (int)$_GET['group_id'] < 1) {
+            // return empty..
+            $this->jdata(array());
+            //$this->jerr("NO GROUP");
+        }
+         if (!$this->hasPerm('Core.Groups', 'S')) {
+                $this->jerr("PERMISSION DENIED");
+            }
+        
+        // this is a paging view...
+        // does 2 queries - one for users,
+        // second just flags if they are members..
+        
+        // Groups are only usable by owner company!!!
+        
+        $u = DB_DataObject::factory('Person');
+        $u->company_id = $this->company->id;
+        //$this->setFilters($u,$_GET);
+        $u->active = 1; // active staff only..
+        
+        $total = $u->count();
+        // build join if req.
+        
+        
+        // sorting..
+        
+        
+        $sort = empty($_REQUEST['sort']) ? '' : $_REQUEST['sort'];
+        $dir = (empty($_REQUEST['dir']) || $_REQUEST['dir'] == 'ASC' ? 'ASC' : 'DESC');
+        $cols = $u->table();
+        if (strlen($sort) && isset($cols[$sort])) {
+            $sort = $u->tableName() .'.'.$sort . ' ' . $dir ;
+            $u->orderBy($sort );
+        } // else other formatas?
+        
+        
+        $u->limit(
+            empty($_REQUEST['start']) ? 0 : (int)$_REQUEST['start'],
+            empty($_REQUEST['limit']) ? 25 : (int)$_REQUEST['limit']
+        );
+        $u->find();
+        $ret = array();
+        $e=-1;
+        while ($u->fetch()) {
+            $ret[$u->id] = array(
+                'id'=> $e--, 
+                'person_id' => $u->id,                 
+                'name' => $u->name , 
+                'isMember' => 0
+            );
+        }
+        
+        if (!$ret) {
+            return $this->jdata($ret,$total);
+        }
+        
+        
+        
+        $p = DB_DataObject::factory('Group_Members');
+        $p->group_id = (int)$_GET['group_id'];
+        $p->whereAdd('user_id IN ('. implode(',' ,array_keys($ret) ). ')');
+        $p->find();
+         
+        
+        while ($p->fetch()) {
+            $ret[$p->user_id]['id'] = $p->id;
+            $ret[$p->user_id]['isMember'] = 1;
+        }
+         
+        $this->jdata(array_values($ret),$total);
+        
+         
+    }
+    
+    function post()
+    {
+        if (empty($_POST['group_id']) || (int)$_POST['group_id'] < 1) {
+            $this->jerr("NO GROUP");
+        }
+        
+        if (!$this->hasPerm( 'Core.Groups','E')) { // editing groups..
+            $this->jerr("PERMISSION DENIED");
+        }
+        
+        
+          // NEW DRAG DROP INTERFACE.
+        if (!empty($_POST['action'])) {
+            // add
+            $ar = explode(',', $_POST['user_ids']);
+            $ac = $_POST['action'];
+            $g = DB_DataObject::factory('Groups');
+            $g->get($_POST['group_id']);
+            // check type????
+            foreach($ar as $uid) {
+                $pi = DB_DataObject::factory('Person');
+                $pi->get($uid);
+                    
+                $p = DB_DataObject::factory('Group_Members');
+                $p->group_id = (int)$_POST['group_id'];
+                $p->user_id = $uid;
+                //$p->type = (int)$_POST['type'];
+                $p->find(true);
+                if (($ac == 'sub') && $p->id) {
+                    if ($g->leader == $pi->id) {
+                        continue;
+                    }
+                    $this->addEvent("DELETE", $p, $g->toEventString(). " Removed " . $pi->toEventString());
+                    $p->delete();
+                    continue;
+                }
+                if (($ac == 'add') && !$p->id) {
+                   
+                    $p->insert();
+                    $this->addEvent("ADD", $p, $g->toEventString(). " Added " . $pi->toEventString());
+                    continue;
+                }
+                
+            }
+            $this->jok("OK");
+        }
+        ///---------------- DEPERCIEATED...
+        // add or update..
+        if (!empty($_POST['dataDelete'])) {
+           
+            
+            foreach($_POST['dataDelete'] as $id => $ac) {
+                $m = DB_DataObject::factory('Group_Members');
+                $m->get($id);
+                $m->delete();
+            }
+        }
+        
+        
+        if (!empty($_POST['dataAdd'])) {
+             
+            foreach($_POST['dataAdd'] as $id => $ac) {
+                $p = DB_DataObject::factory('Group_Members');
+                $p->group_id = (int)$_POST['group_id'];
+                $p->user_id = $id;
+                $p->insert();
+            }
+        }
+        $this->jok("done");
+        
+        
+        
+    }
+     
+    
+    
+    
+}
\ No newline at end of file
diff --git a/Pman.Dialog.Companies.js b/Pman.Dialog.Companies.js
new file mode 100644 (file)
index 0000000..e95e2cf
--- /dev/null
@@ -0,0 +1,483 @@
+//<script type="text/javascript">
+
+
+Pman.Dialog.Companies =   new Roo.util.Observable({
+    events : {
+        'beforerender' : true, // trigger so we can add modules later..
+        'show' : true, // trigger on showing form.. - to load additiona data..
+        'beforesave' : true
+    },
+     
+    dialog : false,
+    form : false,
+    callback: false,
+    create: function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        
+        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  { 
+            autoCreated: true,
+            title: "Edit Companies",
+            modal: true,
+            width:  750,
+            height: 400,
+            shadow:true,
+            minWidth:200,
+            minHeight:180,
+            //proxyDrag: true,
+            collapsible : false,
+            closable: false,
+            draggable: false,
+            center: {
+                autoScroll:false,
+                titlebar: false,
+               // tabPosition: 'top',
+                hideTabs: true,
+                closeOnTab: true,
+                alwaysShowTabs: false
+            }
+        });
+        this.dialog.addKeyListener(27, this.dialog.hide, this.dialog);
+        this.dialog.addButton("Cancel", this.dialog.hide, this.dialog);
+       
+        this.dialog.addButton("Save", this.save, this);
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+        var _this = this;
+        
+        this.form = new Ext.form.Form({
+            labelWidth: 150 ,
+              
+            fileUpload : true,
+            listeners : {
+                actionfailed : function(f, act) {
+                    _this.dialog.el.unmask();
+                    // error msg???
+                    Pman.standardActionFailed(f,act);
+                              
+                },
+                actioncomplete: function(f, act) {
+                    _this.dialog.el.unmask();
+                    //console.log('load completed'); 
+                    // error messages?????
+                    
+                   
+                    if (act.type == 'load') {
+                        
+                        _this.data = act.result.data;
+                        var meth = _this.data.isOwner || !Pman.Login.isOwner() ? 'disable' : 'enable';
+                     
+                            
+                        if (_this.form.findField('comptype')) {
+                            _this.form.findField('comptype')[meth]();
+                        }
+                         
+                       // _this.loaded();
+                        return;
+                    }
+                    
+                    
+                    if (act.type == 'submit') { // only submitted here if we are 
+                        _this.dialog.hide();
+                       
+                        if (_this.callback) {
+                            _this.callback.call(this, act.result.data);
+                        }
+                        return; 
+                    }
+                    // unmask?? 
+                }
+            }
+        
+            
+            
+             
+        });
+        //?? will this work...
+        
+        this.form.addxtype.apply(this.form, this.getFormFields());
+         this.fireEvent('beforeRender', this );
+        
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+         
+        this.form.render(ef.dom);
+
+        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+          
+        
+        
+        
+        this.layout.endUpdate();
+    },
+    show : function (data, callback)
+    {
+        this.callback = callback;
+        this._id = data.id ? data.id : 0;  // modify if you do not use ID !!!!
+        this.create();
+        this.data = data;
+        this.form.reset();
+        if (data._fetch) {
+            this.dialog.show();
+            this.dialog.el.mask("Loading");
+            this.form.doAction('load', {
+                url: baseURL + '/Roo/Companies.html',
+                method: 'GET',
+                params: {
+                    _id: this._id ,
+                    _ts : Math.random()
+                } 
+            });
+            this.fireEvent('show');
+            return;
+        } else {
+            this.form.setValues(data);
+        }
+        
+        
+        
+        this.dialog.show();
+        
+        if (data.isOwner || !Pman.Login.isOwner()) {
+            this.dialog.setTitle("Your Company Details");
+            if (this.form.findField('comptype')) {
+                this.form.findField('comptype').disable();
+            }
+            
+            
+            
+            
+        } else {
+            this.dialog.setTitle(data.id ? "Edit Company" : "Add Company");
+            if (this.form.findField('comptype')) {
+                this.form.findField('comptype').enable();
+            }
+        }
+        this.fireEvent('show');
+
+    },
+    
+    
+    save : function()
+    {
+        this.form.fileUpload = this.form.findField('imageUpload') ? true : false;
+        this.fireEvent('beforesave'); 
+        this.form.doAction('submit', {
+            url: baseURL + '/Roo/Companies.html',
+            method: 'POST',
+            params: {
+                _id: this._id ,
+                ts : Math.random()
+            } 
+        });
+    },
+    
+    comptypeList : function()
+    {
+        // should probably be system configurable..
+        return [
+            
+            [ 'CONSULTANT', "Consultant" ],
+            [ 'CLIENT'    ,  "Client" ],
+            [ 'CONTRACTOR' , "Contractor" ],
+          //  [ 'OWNER', "System Owner" ]
+         ];
+    },
+    comptypeListToString: function(v) {
+        if (!v.length) {
+            return '';
+        }
+        if (v== "OWNER") {
+            return "System Owner";
+        }
+        var a = this.comptypeList();
+        var ret = '';
+        Roo.each(a, function( ar) {
+            if (ar[0] == v) {
+                ret = ar[1];
+                return false;
+            }
+        });
+        return ret;
+        
+        
+        
+    },
+    
+    getFormFields : function() {
+        return [
+            {   
+                xtype : 'Column',
+                width: 500,
+                items: [
+                    this.c_code(),
+                    this.c_comptype_name(),
+                    this.c_name(),
+                    this.c_tel(),
+                    this.c_fax(),
+                    this.c_email(),
+                    
+                    
+                    this.c_address(),
+                    this.c_remarks(),
+                ]
+            },
+            {   
+                xtype : 'Column',
+                width: 200,
+                labelAlign: 'top',
+                items : [
+                    this.c_background_color(),
+                    this.c_image_edit()
+                    //this.c_image_view(),
+                    //this.c_image_change(),
+                ]
+            },
+            this.c_isOwner(),
+            this.c_id()
+        ];
+    },
+    
+    
+    c_code : function() {
+        return {
+                name : 'code',
+                fieldLabel : "Company ID (for filing Ref.)",
+                value : '',
+                allowBlank : false,
+                qtip : "Enter code",
+                xtype : 'TextField',
+                width : 100
+            }
+    },
+    c_comptype_name : function() {
+        return {
+                       
+                               fieldLabel : 'Type',
+                               disabled : Pman.Login.isOwner() ? false : true,
+                name : 'comptype_name',
+                xtype : 'ComboBox',
+                allowBlank : false,
+                               qtip : 'Select Company type',
+                
+                width: 200,
+                xns : Roo.form,
+                
+                listWidth : 250,
+                
+               
+                store: {
+                    xtype : 'SimpleStore',
+                    fields: ['val', 'desc'],
+                    data : this.comptypeList()
+                },
+                displayField:'desc',
+                valueField: 'val',
+                hiddenName : 'comptype',
+                
+                typeAhead: false,
+                editable: false,
+                //mode: 'local',
+                triggerAction: 'all',
+                emptyText: "Select Type",
+                selectOnFocus: true
+                
+                
+           }
+    },
+    c_name : function() {
+        return {
+    
+                name : 'name',
+                fieldLabel : "Company Name",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Company Name",
+                xtype : 'TextField',
+                width : 300
+                    }
+    },
+    c_tel : function() {
+        return {
+    
+                name : 'tel',
+                fieldLabel : "Phone",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Phone Number",
+                xtype : 'TextField',
+                width : 300
+                    }
+    },
+    c_fax : function() {
+        return {
+    
+                name : 'fax',
+                fieldLabel : "fax",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter fax Number",
+                xtype : 'TextField',
+                width : 300
+                    }
+    },
+    c_email : function() {
+        return {
+    
+                name : 'email',
+                fieldLabel : "Email",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Email Address",
+                xtype : 'TextField',
+                width : 300
+                    }
+    },
+    c_address : function() {
+        return {
+    
+                name : 'address',
+                fieldLabel : "Address",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Address",
+                xtype : 'TextArea',
+                height : 70,
+                width : 300
+        }
+    },
+    c_remarks : function() {
+        return {
+    
+                name : 'remarks',
+                fieldLabel : "Remarks",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter remarks",
+                xtype : 'TextArea',
+                height : 40,
+                width : 300
+        }
+    },
+    c_background_color : function() {
+        return {
+                    xtype: 'ColorField',
+                name : 'background_color',
+                fieldLabel: "Background Colour"
+        }
+    },
+    c_image_view : function() {
+        var _this = this;
+        return {
+                xtype :  'FieldSetEx',
+                name : 'image-view',
+                collapseGroup : 'companies-image',
+                value: 0,
+                labelWidth: 100,
+                expanded: true,
+                style: 'width:420px;',
+                legend : "Logo Image",
+                items: [
+                    {
+                        xtype :  'DisplayImage', // image preview...
+                        name : 'logo_id',
+                        fieldLabel : 'Logo Image',
+                        width: 300,
+                        height: 50,
+                        renderer : function(v) {
+                            return v ?  String.format('<img src="{0}" height="{1}">', 
+                                baseURL + '/Images/' + v + '/' + _this.data.logo_id_filename, 
+                                Math.min(this.height, _this.data.logo_id_height)) : "No Image Attached";
+                            
+                        }
+                    }
+                ]
+                
+        }
+    },
+    c_image_edit : function() {
+        var _this = this;
+        return {
+                    name : 'logo_id',
+                    fieldLabel : "Logo Image",
+                    value : '',
+                    allowBlank : true,
+                    style: 'border: 1px solid #ccc;',
+                    xtype : 'DisplayImage',
+                    width : 170,
+                    height: 170,
+                    addTitle : "Change / Add Image",
+                    icon: Roo.rootURL + 'images/default/dd/drop-add.gif',
+                    handler : function() {
+                        var _t = this;
+                         
+                        Pman.Dialog.Image.show({
+                            onid :_this.data.id,
+                            ontable : 'Companies',
+                            imgtype : '-LOGO'
+                        }, function(data) {
+                            if  (data) {
+                                _t.setValue(data.id);
+                            }
+                            
+                        });
+                    }, 
+                    renderer : function(v) {
+                        //var vp = v ? v : 'Companies:' + _this.data.id + ':-LOGO';
+                        if (!v) {
+                            return "No Image Available" + '<BR/>';
+                        }
+                        return String.format('<img src="{0}" width="150">', 
+                                baseURL + '/Images/Thumb/150x150/' + v + '/logo.jpg'
+                        );
+                    }
+            
+            }  ;
+        
+    },
+    c_image_change: function() {
+        return { 
+                xtype :  'FieldSetEx',
+                collapseGroup : 'companies-image',
+                name : 'image-change',
+                value: 0,
+                labelWidth: 100,
+                expanded: false,
+                style: 'width:420px;',
+                legend : "Add / Change Image",
+                items : [ 
+                    {   
+                        xtype :  'TextField',
+                        name : 'imageUpload',
+                        fieldLabel : "Upload Image",
+                        inputType : 'file'
+                    }
+                ]
+        }
+    },
+    c_isOwner : function() {
+        return {                 
+                name : 'isOwner',
+                value : '',
+                xtype : 'Hidden'
+            }
+    },
+    c_id : function() {
+        return { 
+                name : 'id',
+                value : '',
+                xtype : 'Hidden'
+            }
+    }
+         
+});
diff --git a/Pman.Dialog.Document_Types.js b/Pman.Dialog.Document_Types.js
new file mode 100644 (file)
index 0000000..309c72e
--- /dev/null
@@ -0,0 +1,166 @@
+//<script type="text/javascript">
+
+Pman.Dialog.Document_Types = {
+    dialog : false,
+    form : false,
+    create: function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        
+        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  { 
+            autoCreated: true,
+            title: "Edit Document Type",
+            modal: true,
+            width:  650,
+            height: 250,
+            shadow:true,
+            minWidth:200,
+            minHeight:180,
+            //proxyDrag: true,
+            closable: false,
+            draggable: false,
+            center: {
+                autoScroll:false,
+                titlebar: false,
+               // tabPosition: 'top',
+                hideTabs: true,
+                closeOnTab: true,
+                alwaysShowTabs: false
+            }
+        });
+        this.dialog.addKeyListener(27, this.dialog.hide, this.dialog);
+        this.dialog.addButton("Cancel", this.dialog.hide, this.dialog);
+       
+        this.dialog.addButton("Save", this.save, this);
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+        var dg = Pman.Dialog.Document_Types;
+        
+        this.form = new Ext.form.Form({
+            labelWidth: 250 ,
+            listeners : {
+                actionfailed : function(f, act) {
+                    dg.dialog.el.unmask();
+                    // error msg???
+                    
+                    Pman.standardActionFailed(f,act);
+                              
+                },
+                actioncomplete: function(f, act) {
+                    dg.dialog.el.unmask();
+                    //console.log('load completed'); 
+                    // error messages?????
+                    
+                   
+                    if (act.type == 'load') {
+                        
+                        dg.data = act.result.data;
+                       // dg.loaded();
+                        return;
+                    }
+                    
+                    
+                    if (act.type == 'submit') { // only submitted here if we are 
+                        dg.dialog.hide();
+                        if (dg.callback) {
+                            dg.callback.call(this, act.result.data);
+                        }
+                        return; 
+                    }
+                    // unmask?? 
+                }
+            }
+        
+            
+            
+             
+        });
+        //?? will this work...
+        this.form.addxtype.apply(this.form,[{
+                name : 'code',
+                fieldLabel : "Code",
+                value : '',
+                allowBlank : false,
+                qtip : "Enter code",
+                xtype : 'TextField',
+                width : 100
+            },{
+                name : 'name',
+                fieldLabel : "Document Type",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Document Type",
+                xtype : 'TextField',
+                width : 300
+            },{
+                name : 'remarks',
+                fieldLabel : "Remarks",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter remarks",
+                xtype : 'TextArea',
+                height : 100,
+                width : 300
+            },{
+                name : 'id',
+                value : '',
+                xtype : 'Hidden'
+                
+           
+            }
+        ]);
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+         
+        this.form.render(ef.dom);
+
+        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+          
+
+        
+        
+        this.layout.endUpdate();
+    },
+    _id : 0,
+    show: function (data, callback)
+    {
+        
+        this.callback = callback;
+        this._id = data.id ? data.id : 0;  // modify if you do not use ID !!!!
+        this.create();
+        this.form.reset();
+        
+        this.form.setValues(data);
+        
+        this.dialog.show();
+        
+
+    },
+     
+    save : function()
+    {
+         this.form.doAction('submit', {
+            url: baseURL + '/Roo/Document_Types.html',
+            method: 'POST',
+            params: {
+                _id: this._id ,
+                ts : Math.random()
+            } 
+        });
+    }
+    
+    
+    
+    
+         
+};
\ No newline at end of file
diff --git a/Pman.Dialog.Image.js b/Pman.Dialog.Image.js
new file mode 100644 (file)
index 0000000..6865d74
--- /dev/null
@@ -0,0 +1,210 @@
+//<script type="text/javascript">
+
+Pman.Dialog.Image = {
+    dialog : false,
+    form : false,
+    create: function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        var _this = this;
+        
+        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  { 
+            autoCreated: true,
+            title: "Upload Image or  File",
+            modal: true,
+            width:  500,
+            height: 140,
+            shadow:true,
+            minWidth:200,
+            minHeight:180,
+            //proxyDrag: true,
+            closable: false,
+            draggable: false,
+            center: {
+                autoScroll:false,
+                titlebar: false,
+               // tabPosition: 'top',
+                hideTabs: true,
+                closeOnTab: true,
+                alwaysShowTabs: false
+            }
+        });
+        this.dialog.addKeyListener(27, this.dialog.hide, this.dialog);
+        this.dialog.addButton("Cancel", this.dialog.hide, this.dialog);
+       
+        this.dialog.addButton("Save", this.save, this);
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+         
+        this.form = new Ext.form.Form({
+            labelWidth: 150 ,
+            fileUpload : true,
+            listeners : {
+                actionfailed : function(f, act) {
+                    _this.uploadComplete = true;
+                    _this.dialog.el.unmask();
+                    // error msg???
+                    
+                    if (act.type == 'submit') {
+                        Ext.MessageBox.alert("Error", "Saving failed = fix errors and try again");
+                        return;
+                    }
+                    
+                    // what about load failing..
+                    Ext.MessageBox.alert("Error", "Error loading details"); 
+                              
+                },
+                actioncomplete: function(f, act) {
+                    _this.uploadComplete = true;
+                    _this.dialog.el.unmask();
+                     
+                   
+                    if (act.type == 'load') {
+                        
+                        _this.data = act.result.data;
+                       // _this.loaded();
+                        return;
+                    }
+                    
+                    
+                    if (act.type == 'submit') { // only submitted here if we are 
+                        _this.dialog.hide();
+                        //console.log(act);
+                        if (_this.callback) {
+                            _this.callback.call(this, act.result.data);
+                        }
+                        return; 
+                    }
+                    // unmask?? 
+                }
+            }
+        
+            
+            
+             
+        });
+        //?? will this work...
+        this.form.addxtype.apply(this.form,
+            [
+                // type filed??
+                { name: 'UPLOAD_IDENTIFIER' , xtype: 'Hidden' },
+                { 
+                        xtype :  'TextField',
+                        name : 'imageUpload',
+                        fieldLabel : "Upload Image or File",
+                        inputType : 'file'
+                },
+                { name: 'ontable', xtype: 'Hidden' },
+                { name: 'onid', xtype: 'Hidden' },
+                { name: 'imgtype', xtype: 'Hidden' }, // special value for sorting!!
+                { name: 'post_max_size', xtype: 'Hidden' , value :'32M'} ,
+                { name: 'upload_max_filesize', xtype: 'Hidden' , value :'32M'} 
+                    
+                   
+                 
+        ]
+
+        );
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+         
+        this.form.render(ef.dom);
+
+        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+          
+
+        
+        
+        this.layout.endUpdate();
+    },
+    _id : 0,
+    
+    show: function (data, callback)
+    {
+        
+        this.callback = callback;
+         this.create();
+        this.form.reset();
+        
+        this.form.setValues(data);
+        this.form.findField('UPLOAD_IDENTIFIER').setValue((new Date() * 1) + '' + Math.random());
+        this.dialog.show();
+        
+
+    },
+     
+    save : function()
+    {
+        this.dialog.el.mask("Sending");
+        this.uploadComplete = false;
+        this.form.doAction('submit', {
+            url: baseURL + '/Roo/Images.html',
+            method: 'POST',
+            params: {
+             //   _id: 0 ,
+                ts : Math.random()
+            } 
+        });
+        this.haveProgress = false,
+        this.uploadProgress.defer(1000, this);
+        
+    },
+    uploadComplete : false,
+    haveProgress: false,
+    uploadProgress : function()
+    {
+        if (!this.haveProgress) {
+            Roo.MessageBox.progress("Uploading", "Uploading");
+        }
+        if (this.uploadComplete) {
+            Roo.MessageBox.hide();
+            return;
+        }
+        this.haveProgress = true;
+        var _this = this;
+        var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
+        Pman.request({
+            url : baseURL + '/Core/UploadProgress.php',
+            params: {
+                id : uid
+            },
+            method: 'GET',
+            success : function(data){
+                //console.log(data);
+                if (_this.uploadComplete) {
+                    Roo.MessageBox.hide();
+                    return;
+                }
+                    
+                if (data){
+                    Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
+                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
+                    );
+                }
+                _this.uploadProgress.defer(2000, _this);
+            },
+            failure: function(data) {
+              //  console.log('fail');
+             //   console.log(data);
+            }
+        })
+        
+        
+        
+    }
+    
+    
+    
+    
+         
+};
diff --git a/Pman.Dialog.Office.js b/Pman.Dialog.Office.js
new file mode 100644 (file)
index 0000000..d10652e
--- /dev/null
@@ -0,0 +1,193 @@
+//<script type="text/javascript">
+
+  
+Pman.Dialog.Office = {
+    dialog : false,
+    form : false,
+    create: function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        
+        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  { 
+            autoCreated: true,
+            title: "Edit Office / Department / Sub Company",
+            modal: true,
+            width:  650,
+            height: 400,
+            shadow:true,
+            minWidth:200,
+            minHeight:180,
+            //proxyDrag: true,
+            closable: false,
+            draggable: false,
+            center: {
+                autoScroll:false,
+                titlebar: false,
+               // tabPosition: 'top',
+                hideTabs: true,
+                closeOnTab: true,
+                alwaysShowTabs: false
+            }
+        });
+        this.dialog.addKeyListener(27, this.dialog.hide, this.dialog);
+        this.dialog.addButton("Cancel", this.dialog.hide, this.dialog);
+       
+        this.dialog.addButton("Save", this.save, this);
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+        var dg = Pman.Dialog.Office;
+        
+        this.form = new Ext.form.Form({
+            labelWidth: 250 ,
+            listeners : {
+                actionfailed : function(f, act) {
+                    dg.dialog.el.unmask();
+                    // error msg???
+                    
+                    Pman.standardActionFailed(f,act);
+                              
+                },
+                actioncomplete: function(f, act) {
+                    dg.dialog.el.unmask();
+                    //console.log('load completed'); 
+                    // error messages?????
+                    
+                   
+                    if (act.type == 'load') {
+                        
+                        dg.data = act.result.data;
+                       // dg.loaded();
+                        return;
+                    }
+                    
+                    
+                    if (act.type == 'submit') { // only submitted here if we are 
+                        dg.dialog.hide();
+                        if (dg.callback) {
+                            dg.callback.call(this, act.result.data);
+                        }
+                        return; 
+                    }
+                    // unmask?? 
+                }
+            }
+        
+            
+            
+             
+        });
+        //?? will this work...
+        this.form.addxtype.apply(this.form,[{
+                'name' : 'id',
+                'value' : '',
+                'xtype' : 'Hidden'
+                
+            },{
+                'name' : 'company_id',
+              
+                'value' : '',
+                'xtype' : 'Hidden'
+            },{
+                'name' : 'company_id_name',
+                'fieldLabel' : "Company",
+                'value' : '',
+                'xtype' : 'TextField',
+                readOnly : true,
+                
+                'width' : 300
+            },
+            {
+                'name' : 'name',
+                'fieldLabel' : "Office / Department / Sub Comp. Name",
+                'value' : '',
+                'allowBlank' : false,
+                'qtip' : "Enter name",
+                'xtype' : 'TextField',
+                'width' : 300
+            },{
+                'name' : 'address',
+                'fieldLabel' : "Address",
+                'value' : '',
+                 
+                'qtip' : "Enter address",
+                'xtype' : 'TextArea',
+                'height' : 100,
+                'width' : 300
+            },{
+                'name' : 'phone',
+                'fieldLabel' : "Phone",
+                'value' : '',
+                
+                'qtip' : "Enter phone",
+                'xtype' : 'TextField',
+                'width' : 300
+            },{
+                'name' : 'fax',
+                'fieldLabel' : "fax",
+                'value' : '',
+                
+                'qtip' : "Enter fax",
+                'xtype' : 'TextField',
+                'width' : 300
+            },{
+                'name' : 'email',
+                'fieldLabel' : "Email",
+                'value' : '',
+             
+                'qtip' : "Enter email",
+                'xtype' : 'TextField',
+                'width' : 300
+            }
+        ]);
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+         
+        this.form.render(ef.dom);
+
+        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+          
+
+        
+        
+        this.layout.endUpdate();
+    },
+    _id : 0,
+    show : function(data, callback)
+    {
+        this.callback= callback;
+        this._id = data.id;
+        this.create();
+        this.form.reset();
+        
+        
+        this.form.setValues(data);
+        this.dialog.show();
+        this.form.findField('name').focus();
+        
+
+    },
+    save : function()
+    {
+         this.form.doAction('submit', {
+            url: baseURL + '/Roo/Office.html',
+            method: 'POST',
+            params: {
+                _id: this._id ,
+                ts : Math.random()
+            } 
+        });
+    } 
+    
+    
+         
+};
diff --git a/Pman.Dialog.Person.js b/Pman.Dialog.Person.js
new file mode 100644 (file)
index 0000000..59e5f8f
--- /dev/null
@@ -0,0 +1,29 @@
+//<script type="text/javascript">
+// for needed for new person in External contacts...
+
+
+
+// needs adding to init!!!!
+Pman.on('beforeload', function() {
+  
+   
+    // new - office / company readonly
+    Pman.Dialog.Person  = new Pman.Dialog.PersonEditor({
+        type : 'edit2',
+        dialogConfig : {
+            title: "Edit Contact Details", 
+            height: 400 // slightly taller..
+
+        },
+        itemList : [
+            
+            'company_id_name_ro',
+            'office_id_name_ro',
+            'name','role', 'phone', 'fax', 'email',
+            'id',  'office_id', 'company_id',
+            
+            // not really needed??
+            'company_id_email','company_id_address','company_id_tel','company_id_fax'
+        ]
+    });
+});
\ No newline at end of file
diff --git a/Pman.Dialog.PersonEdit.js b/Pman.Dialog.PersonEdit.js
new file mode 100644 (file)
index 0000000..a130cbf
--- /dev/null
@@ -0,0 +1,30 @@
+//<script type="text/javascript">
+// for needed for new person in External contacts...
+
+
+
+// needs adding to init!!!!
+Pman.on('beforeload', function() {
+    
+    // edit - company readonly /office  - selectable..
+    // CONTACTS!!!!!
+    Pman.Dialog.PersonEdit = new Pman.Dialog.PersonEditor({
+        type : 'edit',
+        dialogConfig : {
+            title: "Edit Contact Details",
+            height: 350 // slightly taller..
+            
+        },
+        itemList : [
+            'company_id_name',
+            'office_id_name',
+            'name','role', 'phone', 'fax', 'email',
+       
+            'passwd1', 'passwd2',
+            'id', 
+            //'company_id', 
+            'company_id_email',
+            'company_id_address','company_id_tel','company_id_fax'
+        ]
+    });
+});
\ No newline at end of file
diff --git a/Pman.Dialog.PersonEditor.js b/Pman.Dialog.PersonEditor.js
new file mode 100644 (file)
index 0000000..e66dbbe
--- /dev/null
@@ -0,0 +1,751 @@
+//<script type="text/javascript">
+
+Pman.Dialog.PersonEditor = function(config)
+{
+   
+    Roo.apply(this, config);
+    
+};
+
+Pman.Dialog.PersonEditor.prototype = {
+    
+    itemList : false, // list of itemTypes used on form.
+    dialogConfig : false, // 
+    type : '',
+    
+    
+    itemTypes : false, // set in contructor
+    
+    dialog : false,
+    form : false,
+    layout : false,
+    
+    callback: false, 
+    _id : false,
+    data : false,
+    
+    
+    create : function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        var _this = this;
+        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  
+            Roo.apply({ 
+                autoCreated: true,
+                title: 'Edit Contact Details',
+                modal: true,
+                width:  530,
+                height: 300,
+                shadow:true,
+                minWidth:200,
+                minHeight:180,
+                //proxyDrag: true,
+                closable: false,
+                draggable: false,
+                center: {
+                    autoScroll:false,
+                    titlebar: false,
+                   // tabPosition: 'top',
+                    hideTabs: true,
+                    closeOnTab: true,
+                    alwaysShowTabs: false
+                }
+            },this.dialogConfig)
+        );
+        
+        this.dialog.addKeyListener(27, this.dialog.hide, this.dialog);
+        if (this.itemList.indexOf('save_send') > -1 ) {
+            this.dialog.addButton("Send Introduction Mail", this.saveSend, this);
+        }
+        
+        this.dialog.addButton("Cancel", this.dialog.hide, this.dialog);
+        
+        
+        
+        this.dialog.addButton("Save", this.save, this);
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+         
+        this.form = new Ext.form.Form({
+            labelWidth: 120,
+            listeners : {
+                actionfailed : function(f, act) {
+                    _this.dialog.el.unmask();
+                    // error msg???
+                    Pman.standardActionFailed(f,act);
+                              
+                },
+                actioncomplete: function(f, act) {
+                    _this.dialog.el.unmask();
+                    if (act.type == 'load') {
+                        _this.data = act.result.data;
+                         
+                    }
+                    
+                                
+                    if  ((act.type == 'load') || (act.type == 'setdata')) {
+                        var data = _this.data;
+                        // we dont have  a form where company name is sent in - and is editable..
+                        //this.form.findField('office_id')
+                        
+                        if (_this.form.findField('company_id') && _this.form.findField('company_id').setFromData) {
+                            _this.form.findField('company_id').setFromData( data.company_id ? {
+                                id : data.company_id,
+                                name : data.company_id_name,
+                                remarks:  data.company_id_remarks,
+                                address:  data.company_id_address,
+                                tel:  data.company_id_tel,
+                                fax:  data.company_id_fax,
+                                email:  data.company_id_email
+                            } : { id: 0, name : ''  });
+                        }
+                        
+                        
+                        if (_this.form.findField('office_id') && _this.form.findField('office_id').setFromData) {
+                            // set up the office details.. new, edit, staff
+                            
+                            _this.form.findField('office_id').setFromData(data.office_id ? { 
+                                id: data.office_id,
+                                name:  data.office_id_name,
+                                remarks:  data.office_id_remarks,
+                                address:  data.office_id_address,
+                                tel:  data.office_id_tel,
+                                fax:  data.office_id_fax,
+                                email:  data.office_id_email
+                                // should we add in company_name etc. ????
+                                
+                            } :  {  id: 0, name:  ''  });
+                            
+                        }
+                        if (_this.form.findField('project_id')) {
+                            _this.form.findbyId('project_id_fs').setExpand(data.project_id ? true: false);
+                            
+                            
+                            _this.form.findField('project_id').setFromData(data.project_id ?{
+                               id : data.project_id,
+                               code : data.project_id_code
+                              } : { id: 0, code :'' } );
+                       }
+                        
+                        
+                        if (this.type == 'staff') {
+                            _this.form.findField('passwd1').allowBlank = false;
+                            _this.form.findField('passwd2').allowBlank = false;
+                            if (data.id > 0) {
+                                _this.form.findField('passwd1').allowBlank = true;
+                                _this.form.findField('passwd2').allowBlank = true;
+                            }
+
+                        }
+                        return;
+                    } 
+                    
+                    if (act.type == 'submit') { // only submitted here if we are 
+                        _this.dialog.hide();
+                        
+                        
+                        
+                        if (_this.callback) {
+                            _this.callback.call(this, act.result.data);
+                        }
+                        if (_this.sendAfterSave) {
+                            act.result.data.rawPasswd = _this.form.findField('passwd1').getValue();
+                            _this.sendIntro([ act.result.data ], "Sending Welcome Message");
+                        }
+                        
+                        return; 
+                    }
+                    // unmask?? 
+                }
+            }
+         
+             
+        });
+        this.loadItemTypes();
+        Roo.each(this.itemList, function(il) {
+            if (typeof(il) != 'object') {
+                _this.form.addxtype(_this.itemTypes[il]);
+                return true;
+            }
+            _this.form.addxtype(Roo.apply(il, _this.itemTypes[il.name]));
+            
+        });
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+         
+        this.form.render(ef.dom);
+
+        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+          
+
+        
+        
+        this.layout.endUpdate();
+    },
+    
+    
+    loadItemTypes : function() 
+    {
+        var _this = this;
+        this.itemTypes =   {
+            company_id_name_ro : {
+                    name : 'company_id_name',
+                    fieldLabel : "Company",
+                    value : '',
+                    xtype : 'TextField',
+                    readOnly : true,
+                    width : 300
+            },
+            
+            company_id_name : {
+                
+                xtype: 'ComboBoxAdder',
+                fieldLabel: "Company",
+                name : 'company_id_name',
+                selectOnFocus:true,
+                qtip : "Select Company",
+                allowBlank : false,
+                width: 300,
+                
+                store: {
+                    xtype : 'Store',
+                      // load using HTTP
+                    proxy:{
+                        xtype:  'HttpProxy',
+                        url: baseURL + '/Roo/Companies.html',
+                        method: 'GET'
+                    },
+                    reader: Pman.Readers.Companies,
+                    listeners : {
+                        beforeload : function(st,o)
+                        {
+                        
+                            o.params.isOwner = 0;
+                        },
+                        loadexception : Pman.loadException
+                    
+                    },
+                    sortInfo: {
+                        field: 'name', direction: 'ASC'
+                    }
+                },
+                displayField:'name',
+                valueField : 'id',
+                hiddenName:  'company_id',
+                typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all',
+                tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '<b>{name}</b> {address}',
+                    '</div>'
+                ),
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                listWidth: 400,
+               
+                minChars: 2,
+                pageSize:20,
+                listeners : {
+                    adderclick : function()
+                    {
+                        var cb = this;
+                        Pman.Dialog.Companies.show( {  id: 0 },  function(data) {
+                            cb.setFromData(data);
+                        }); 
+                    }
+                }
+               
+                 
+                 
+                 
+            },
+            office_id_name_ro : {
+                    name : 'office_id_name',
+                    fieldLabel : "Office",
+                    value : '',
+                    xtype : 'TextField',
+                    readOnly : true,
+                    width : 300
+            },
+            
+            office_id_name : {
+                
+                xtype: 'ComboBoxAdder',
+                fieldLabel: "Office / Department",
+                name : 'office_id_name',
+                selectOnFocus:true,
+                qtip : "Select Office",
+                allowBlank : true,
+                width: 300,
+                
+                store:  {
+                    xtype : 'Store',
+                      // load using HTTP
+                    proxy: {
+                        xtype : 'HttpProxy',
+                        url: baseURL + '/Roo/Office.html',
+                        method: 'GET'
+                    },
+                    reader: Pman.Readers.Office,
+                    listeners : {
+                        beforeload : function(st,o)
+                        {
+                            // compnay myst be set..
+                            var coid = _this.form.findField('company_id').getValue();
+                            o.params.company_id = coid;
+                        },
+                        loadexception : Pman.loadException
+                    
+                    },
+                    sortInfo: {
+                        field: 'name', direction: 'ASC'
+                    }
+                },
+                listeners : {
+                    adderclick : function()
+                    {
+                        var cb = this;
+                        
+                        // for new - we have
+                        var cfg = false;
+                        var data = false;
+                        if (_this.type == 'new') {
+                            data = _this.form.findField('company_id').lastData;
+                            if (!data.id ) {
+                                Ext.MessageBox.alert("Error", "Select An Company First");
+                                return false
+                            }
+                            
+                            cfg = {
+                                company_id : data.id ,
+                                company_id_name: data.name,
+                                address: data.address,
+                                phone: data.tel,
+                                fax: data.fax,
+                                email: data.email
+                            };
+
+                        } else { // all other tyeps have the data in the caller data array.
+                            data  = _this.data;
+                            cfg = {
+                                company_id : data.company_id,
+                                company_id_name: data.company_id_name,
+                                address: data.company_id_address,
+                                phone: data.company_id_tel,
+                                fax: data.company_id_fax,
+                                email: data.company_id_email
+                            }
+                        }
+                        
+                         
+                        
+                        
+                        Pman.Dialog.Office.show(cfg, function(data) {
+                                cb.setFromData(data);
+                        }); 
+                    },
+                    beforequery : function (qe) {
+                        var coid = _this.form.findField('company_id').getValue();
+                        if (coid < 1 ) {
+                            Ext.MessageBox.alert("Error", "Select An Company First");
+                            return false;
+                        }
+                    }
+                },
+                displayField:'name',
+                valueField : 'id',
+                hiddenName:  'office_id',
+                typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all',
+                tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '<b>{name}</b> {address}',
+                    '</div>'
+                ),
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                listWidth: 400,
+               
+                minChars: 2,
+                pageSize:20 
+                 
+                 
+            },
+            name : {
+                name : 'name',
+                fieldLabel : "Contact Name",
+                value : '',
+                allowBlank : false,
+                qtip : "Enter name",
+                xtype : 'TextField',
+                width : 300
+            },
+            role : {
+                name : 'role',
+                fieldLabel : "Role / Position",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Role / Position",
+                xtype : 'TextField',
+                width : 300
+            },
+
+            phone : {
+                name : 'phone',
+                fieldLabel : "Phone",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter phone Number",
+                xtype : 'TextField',
+                width : 300
+            },
+            fax : {
+              
+                name : 'fax',
+                fieldLabel : "Fax",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter fax",
+                xtype : 'TextField',
+                width : 300
+            },
+            email : {
+                name : 'email',
+                fieldLabel : "Email",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter email",
+                xtype : 'TextField',
+                width : 300
+            },
+            bulklist: {
+                name : 'bulklist',
+                fieldLabel : "Email address (one per line)",
+                value : '',
+                allowBlank : false,
+                qtip : "Enter email addresse",
+                xtype : 'TextArea',
+                width : 300,
+                height:  200
+            },
+            
+            
+            email_req : {
+                name : 'email',
+                fieldLabel : "Email",
+                value : '',
+                allowBlank : false,
+                qtip : "Enter email",
+                xtype : 'TextField',
+                width : 300
+            },
+            passwd1 : {
+                name : 'passwd1',
+                fieldLabel : "New Password ",
+                value : '',
+                allowBlank : true, // must be filled in as we rely on it for login details..
+                inputType: 'password',
+                xtype : 'SecurePass',
+                width : 220,
+                imageRoot : rootURL + '/Pman/templates/images'
+            },
+            passwd2 : {
+                
+                name : 'passwd2',
+                fieldLabel : "Password (type again to confirm)",
+                value : '',
+                allowBlank : true, // must be filled in as we rely on it for login details..
+                inputType: 'password',
+                xtype : 'TextField',
+                width : 220
+            },
+            project_id_fs : {
+                xtype : 'FieldSetEx',
+                name: 'project_id_fs',
+                value: 0,
+                labelWidth: 100,
+                expanded: false,
+                style: 'width:420px;',
+                legend : "Always File Messages from this Person in Project",
+                items : [
+                    Pman.Std.project_id({
+                        width: 300,
+                        fieldLabel : "Project",
+                        allowBlank : true
+                    }),
+                    {
+                      xtype: 'ComboBox',
+                        name : 'action_type_str',
+                        selectOnFocus:true,
+                        qtip : "Action Type",
+                        fieldLabel : "Action Required",
+
+                        allowBlank : true,
+                        width: 50,
+                        
+                        
+                        store: new Ext.data.SimpleStore({
+                              // load using HTTP
+                            fields: [ 'code', 'desc' ],
+                            data:  [[ 'ACTION_REQUIRED', "Yes"] , [ 'NOTIFY', "No"] ]
+                        }),
+                        displayField:'desc',
+                        editable : false,
+                        valueField : 'code',
+                        hiddenName:  'action_type',
+                        value : 'ACTION_REQUIRED',
+                        forceSelection: true,
+                        mode: 'local',
+                        triggerAction: 'all' 
+                       // queryParam: 'query[project]',
+                       // loadingText: "Searching...",
+                        //listWidth: 400
+                       
+                         
+                       
+                    }
+                ]
+            },
+            
+            id : { name : 'id', value : '', xtype : 'Hidden' },
+            save_send : { name : '_save_send', value : 0, xtype : 'Hidden' },
+            active : { name : 'active', value : 1, xtype : 'Hidden' },
+            company_id : { name : 'company_id', value : '', xtype : 'Hidden' },
+            company_id_email : { name : 'company_id_email', value : '', xtype : 'Hidden' },
+            company_id_address : { name : 'company_id_address', value : '', xtype : 'Hidden' },
+            company_id_tel : { name : 'company_id_tel', value : '', xtype : 'Hidden' },
+            company_id_fax : { name : 'company_id_fax', value : '', xtype : 'Hidden' },
+            project_id_addto : { name : 'project_id_addto', value : '', xtype : 'Hidden' }
+        };
+    
+    }, //end getItemTypes
+    
+    saveSend : function(bt, e)
+    {
+        this.save(bt,e, 1)
+    },
+    sendAfterSave : 0,
+    save : function(bt, e, andsend)
+    {
+        // ensure a company has been selected..
+        this.sendAfterSave  = andsend || 0;
+        
+        if (this.form.findField('bulklist')) {
+            this.saveBulk();
+            return;
+            
+        }
+        if (!this.form.findField('company_id').getValue()) {
+            Ext.MessageBox.alert("Error", "Select a Company");
+            return;
+        }
+        
+        if (this.form.findField('passwd1')) {
+            
+            var p1 = this.form.findField('passwd1').getValue();
+            var p2 = this.form.findField('passwd2').getValue();
+            
+            if (this.sendAfterSave && !p1.length) {
+                Ext.MessageBox.alert("Error", "You must create a password to send introduction mail");
+                return;
+            }
+            
+            if (Pman.Login.authUser.id < 0 && !p1.length) {
+                Ext.MessageBox.alert("Error", "You must create a password for the admin account");
+                return;
+            }
+            
+            
+            if (p1.length || p2.length) {
+                if (p1 != p2) {
+                    Ext.MessageBox.alert("Error", "Passwords do not match");
+                    return;
+                }
+            }
+            
+        
+        }
+        // ensure it's blank!
+        if (this.form.findField('project_id')) {
+            if (!this.form.findbyId('project_id_fs').expanded) {
+                this.form.findField('project_id').setFromData({
+                    id : 0,
+                    code : ''
+                });
+            }
+        }
+        this.dialog.el.mask("Sending");
+        this.form.doAction('submit', {
+            url: baseURL + '/Roo/Person.html',
+            method: 'POST',
+            params: {
+                _id: this._id ,
+                ts : Math.random()
+            } 
+        });
+    },
+
+    
+     
+    show: function (data, callback)
+    {
+        
+        this.callback = callback;
+        this._id = data.id;
+        this.data = data;
+        this.create();
+        this.form.reset();
+        if (data._fetch) {
+            this.dialog.show();
+            this.dialog.el.mask("Loading");
+            this.form.doAction('load', {
+                url: baseURL + '/Roo/Person.html',
+                method: 'GET',
+                params: {
+                    _id: this._id ,
+                    _ts : Math.random()
+                } 
+            });
+           // this.fireEvent('show');
+            return;
+        } else {
+            this.form.setValues(data);
+        }
+        this.form.fireEvent('actioncomplete', this.form,{
+            type : 'setdata',
+            data: data
+        });
+         
+        this.dialog.show();
+        // no need to load...
+
+    },
+    
+    saveBulk: function() {
+        // similar action to SendIntro
+        // we build a fake list of data..
+        if (!this.form.findField('company_id').getValue()) {
+            Roo.MessageBox.alert("Error", "Select the Company Name");
+            return;
+        }
+        // prompt..
+        var adr = [];
+        var _this = this;
+        
+        Roo.MessageBox.confirm("Send Welcome", "Send Welcome Messages and Generate Passwords?",
+            function(yn) {
+                var pw = 1;
+                //console.log(yn);
+                if (yn != 'yes') {
+                    pw = 0;
+                }
+                Roo.each(_this.form.findField('bulklist').getValue().split("\n"), function(v) {
+                    if (!v.length || !v.replace(new RegExp(' ', 'g'), '').length) {
+                        return;
+                    }
+                    adr.push({
+                        id:  0,
+                        email : v,
+                        company_id : _this.form.findField('company_id').getValue(),
+                        office_id  : _this.form.findField('office_id').getValue(),
+                        active : 1,
+                        _create : 1,
+                        _createPasswd : pw
+                        
+                    })
+                });
+                if (!adr.length) {
+                    Roo.MessageBox.alert("Error", "No addresses found");
+                    return;
+                }
+                _this.dialog.hide();
+                _this.sendIntro(adr, "Creating Account / Sending Welcome", _this.callback)
+            }
+        );
+        
+        
+        
+        
+      
+      
+    },
+    
+    
+    sendIntro  : function(ar, msg, callback) {
+        // can hanlde multiple items -- will be usefull for later usage
+        // when we do list of multiple users..
+        var i =0;
+        
+        Roo.MessageBox.show({
+           title: "Please wait...",
+           msg: msg,
+           width:350,
+           progress:true,
+           closable:false
+        });
+        
+        //this.sendData = ar; console.log(ar);
+        var _this = this;
+        var wis = function () 
+        {
+            if (i == ar.length) {
+                Roo.MessageBox.hide();
+                Roo.MessageBox.alert("Done", "Done - " + msg);
+                if (callback) {
+                    callback.call(this, false);
+                }
+                return;
+            }
+            Roo.MessageBox.updateProgress( 
+                (i+1)/ar.length,  msg + " : " + ar[i].email
+            );
+            
+             
+            var c = ar[i];
+            i++;
+            Pman.request({
+                url : baseURL+'/Core/SendIntro.html',
+                method : 'POST',
+                params: c,
+                success : function(resp, opts) {
+                    wis();
+                },
+                failure: function()
+                {
+                    Roo.MessageBox.show({
+                       title: "Please wait...",
+                       msg: msg,
+                       width:350,
+                       progress:true,
+                       closable:false
+                    });
+                    // error condition!?!?
+                    wis();
+                }
+                
+            });
+            
+        };
+        wis();
+        
+        
+        
+    }
+         
+};
\ No newline at end of file
diff --git a/Pman.Dialog.PersonNew.js b/Pman.Dialog.PersonNew.js
new file mode 100644 (file)
index 0000000..1e73625
--- /dev/null
@@ -0,0 +1,28 @@
+//<script type="text/javascript">
+// for needed for new person in External contacts...
+
+
+
+// needs adding to init!!!!
+Pman.on('beforeload', function() {
+     // new - company/office pulldowns.
+     // used by pman
+    Pman.Dialog.PersonNew = new Pman.Dialog.PersonEditor({
+        type : 'new',
+        dialogConfig : {
+            title: "New Contact Details",
+            height: 350 // slightly taller..
+        },
+        itemList : [
+            'company_id_name',
+            'office_id_name',
+            'name','role', 'phone', 'fax', 'email',
+            'project_id_fs',
+            'id',  
+            'company_id_email',
+            'company_id_address','company_id_tel','company_id_fax', 
+            'project_id_addto' // hidden..
+            
+        ]
+    });
+});
\ No newline at end of file
diff --git a/Pman.Dialog.PersonStaff.js b/Pman.Dialog.PersonStaff.js
new file mode 100644 (file)
index 0000000..aac3fb1
--- /dev/null
@@ -0,0 +1,31 @@
+//<script type="text/javascript">
+// for needed for new person in External contacts...
+
+
+
+// needs adding to init!!!!
+Pman.on('beforeload', function() {
+     
+    Pman.Dialog.PersonStaff  = new Pman.Dialog.PersonEditor({
+        type : 'staff',
+        dialogConfig : {
+            title: "Add / Edit Staff"
+        },
+        itemList : [
+            
+            
+            'office_id_name',
+            'name','role', 'phone', 'fax', 'email_req',
+            'passwd1', 'passwd2',
+            
+            'id',  'office_id', 'company_id',
+            'active',
+            // not really needed??
+            'company_id_email','company_id_address','company_id_tel','company_id_fax'
+        ]
+    });
+    
+    
+    
+});
diff --git a/Pman.Dialog.Projects.js b/Pman.Dialog.Projects.js
new file mode 100644 (file)
index 0000000..23bd56b
--- /dev/null
@@ -0,0 +1,446 @@
+//<script type="text/javascript">
+  
+Pman.Dialog.Projects = {
+    dialog : false,
+    form : false,
+    create: function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        
+        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  { 
+            autoCreated: true,
+            title: "Edit Project",
+            modal: true,
+            width:  450,
+            height: 450,
+            shadow:true,
+            minWidth:200,
+            minHeight:180,
+            //proxyDrag: true,
+            closable: false,
+            draggable: false,
+            center: {
+                autoScroll:false,
+                titlebar: false,
+               // tabPosition: 'top',
+                hideTabs: true,
+                closeOnTab: true,
+                alwaysShowTabs: false
+            }
+        });
+        this.dialog.addKeyListener(27, this.dialog.hide, this.dialog);
+        this.dialog.addButton("Cancel", this.dialog.hide, this.dialog);
+       
+        this.dialog.addButton("Save", this.save, this);
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+        var dg = Pman.Dialog.Projects;
+        
+        this.form = new Ext.form.Form({
+            labelWidth: 100 ,
+            listeners : {
+                actionfailed : function(f, act) {
+                    dg.dialog.el.unmask();
+                    // error msg???
+                    Pman.standardActionFailed(f,act);
+                              
+                },
+                actioncomplete: function(f, act) {
+                    dg.dialog.el.unmask();
+                    //console.log('load completed'); 
+                    // error messages?????
+                    
+                   
+                    if (act.type == 'load') {
+                        
+                        dg.data = act.result.data;
+                       // dg.loaded();
+                        return;
+                    }
+                    
+                    
+                    if (act.type == 'submit') { // only submitted here if we are 
+                        dg.dialog.hide();
+                        if (dg.callback) {
+                            dg.callback.call(this, act.result.data);
+                        }
+                        return; 
+                    }
+                    // unmask?? 
+                }
+            }
+        
+            
+            
+             
+        });
+        //?? will this work...
+        this.form.addxtype.apply(this.form,[
+            
+            {
+                name : 'code',
+                fieldLabel : "Code",
+                value : '',
+                allowBlank : false,
+                qtip : "Enter Project Code",
+                xtype : 'TextField',
+                width : 100
+            },
+            {
+                name : 'name',
+                fieldLabel : "Project Name",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Project Name",
+                xtype : 'TextField',
+                width : 300
+            },
+            {
+                
+                xtype: 'ComboBox',
+                name : 'type_desc',
+                selectOnFocus:true,
+                qtip : "Project type",
+                fieldLabel : "Project type",
+
+                allowBlank : false,
+                width: 200,
+                
+                
+                store: new Ext.data.SimpleStore({
+                      // load using HTTP
+                    fields: [ 'code', 'desc' ],
+                    data: Pman.Tab.ProjectsMgr.getTypes()
+                }),
+                displayField:'desc',
+                editable : false,
+                valueField : 'code',
+                hiddenName:  'type',
+                typeAhead: true,
+                forceSelection: true,
+                mode: 'local',
+                triggerAction: 'all' 
+               // queryParam: 'query[project]',
+               // loadingText: "Searching...",
+                //listWidth: 400
+               
+                 
+               
+            },
+             // CLIENT picklist.
+             {
+                
+                xtype: 'ComboBoxAdder',
+                fieldLabel: "Client",
+                name : 'client_id_name',
+                selectOnFocus:true,
+                qtip : "Select Client",
+                allowBlank : true,
+                width: 277,
+                
+                store: new Ext.data.Store({
+                      // load using HTTP
+                    proxy: new Ext.data.HttpProxy({
+                        url: baseURL + '/Roo/Companies.html',
+                        method: 'GET'
+                    }),
+                    reader: Pman.Readers.Companies,
+                    listeners : {
+                        loadexception : Pman.loadException
+                    }
+                }),
+                displayField:'name',
+                valueField : 'id',
+                hiddenName:  'client_id',
+                typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all',
+                tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '<b>{name}</b> {address}',
+                    '</div>'
+                ),
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                listWidth: 400,
+               
+                minChars: 2,
+                pageSize:20,
+                 
+                listeners : {
+                    adderclick : function()
+                    {
+                        var cb = this;
+                        Pman.Dialog.Companies.show( {  id: 0 },  function(data) {
+                            cb.setFromData(data);
+                        }); 
+                    },
+                    blur : function(f) {
+                        if (!f.el.getValue().length) {
+                            this.setFromData({
+                                id: 0,
+                                name : ""
+                            });
+                        }
+                    }
+                }
+
+                  
+            },
+              // TEAM: picklist
+            {
+                
+                xtype: 'ComboBox',
+                fieldLabel: "Team",
+                name : 'team_id_name',
+                selectOnFocus:true,
+                qtip : "Select Team",
+                allowBlank : true,
+                width: 300,
+                
+                store: new Ext.data.Store({
+                      // load using HTTP
+                    proxy: new Ext.data.HttpProxy({
+                        url: baseURL + '/Roo/Groups.html',
+                        method: 'GET'
+                        
+                    }),
+                    reader: Pman.Readers.Groups,
+                    listeners : {
+                        beforeload: function(g, o) {
+                            o.params = o.params ? o.params : {};
+                            o.params.type = 1;
+                            o.params['query[group_pulldown]'] = 1;
+                            
+                        },
+                        loadexception : Pman.loadException
+                    
+                    }
+                }),
+                displayField:'name',
+                valueField : 'id',
+                hiddenName:  'team_id',
+                typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all' ,
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                //listWidth: 400,
+               
+                minChars: 2,
+               // pageSize:20,
+                
+                listeners : {
+                    blur : function(f) {
+                        if (!f.el.getValue().length) {
+                            this.setFromData({
+                                id: 0,
+                                name : ""
+                            });
+                        }
+                    }
+                }
+                
+                  
+            },
+         
+            // Office (is related to team leader?!?)
+            
+            // Files stored:
+            
+            {
+                name : 'file_location',
+                fieldLabel : "File Location",
+                value : '',
+                qtip : "Where are the files stored?",
+                allowBlank : true,
+                xtype : 'TextField',
+                width : 300
+            },
+            
+            // things to go in..
+            // Location (Files)
+            // Client? - pick from contacts..
+            // team? 
+            // team leaders???
+            // office in charge..
+            // email list????? == oru project list..
+            
+            
+            
+         
+            
+            
+            {
+                name : 'remarks',
+                fieldLabel : "Remarks",
+                value : '',
+                allowBlank : true,
+                qtip : "Enter Project Remarks",
+                xtype : 'TextArea',
+                width : 300,
+                height : 100
+            },
+                 // opened by?
+            // opened date.. 
+            {
+                xtype : 'FieldSet',
+                legend: 'Opened',
+                style: 'width:393px;padding:0 0 2 10;',
+                items : [
+                    {
+                        name : 'open_date',
+                        fieldLabel : "Date",
+                        value : '',
+                        allowBlank : true,
+                        qtip : "Enter Date Opened",
+                        xtype : 'DateField',
+                        altFormats : 'Y-m-d|d/m/Y',
+                        width : 100,
+                        format: 'd/m/Y'
+                    },
+                    
+                    
+                      
+                    {
+                        
+                        xtype: 'ComboBox',
+                        fieldLabel: "By",
+                        name : 'open_by_name',
+                        selectOnFocus:true,
+                        qtip : "Select Person Who opened",
+                        allowBlank : true,
+                        width: 250,
+                        
+                        store: new Ext.data.Store({
+                              // load using HTTP
+                            proxy: new Ext.data.HttpProxy({
+                                url: baseURL + '/Roo/Person.html',
+                                method: 'GET'
+                            }),
+                            reader: Pman.Readers.Person,
+                            listeners : {
+                                beforeload : function(st,o)
+                                {
+                                    // compnay myst be set..
+                                     
+                                    o.params.company_id = Pman.Login.authUser.company_id * 1;
+                                     
+                                     
+                                },
+                                loadexception : Pman.loadException
+                            
+                            }
+                        }),
+                         
+                        
+                        displayField:'name',
+                        valueField : 'id',
+                        hiddenName:  'open_by',
+                        typeAhead: true,
+                        forceSelection: true,
+                        doForce : function(){
+                            if(this.el.dom.value.length > 0){
+                                this.el.dom.value =
+                                    this.lastSelectionText === undefined ? "" : this.lastSelectionText;
+                                this.applyEmptyText();
+                                if (!this.el.dom.value.length) {
+                                    this.setFromData({  id: 0, name:  '----'  });
+                                }
+                            }
+                        },
+
+                        //mode: 'local',
+                        triggerAction: 'all',
+                        tpl: new Ext.Template(
+                            '<div class="x-grid-cell-text x-btn button">',
+                                '<b>{name}</b> {role}',
+                            '</div>'
+                        ),
+                        queryParam: 'query[name]',
+                        loadingText: "Searching...",
+                        listWidth: 300,
+                       
+                        minChars: 2,
+                        pageSize:20 
+                         
+                    }
+                ]
+                 
+            },
+            {
+                name : 'id',
+                value : '',
+                xtype : 'Hidden'
+                
+            }
+        ]);
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+         
+        this.form.render(ef.dom);
+
+        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+          
+
+        
+        
+        this.layout.endUpdate();
+    },
+    _id : 0,
+    show : function(data, callback)
+    {
+        this.callback= callback;
+        this._id = data.id;
+        this.data = data;
+        this.create();
+        this.form.reset();
+        this.form.setValues(data);
+        if (data.id) {
+             
+            this.form.findField('client_id').setFromData({
+                id: data.client_id,
+                name: data.client_id_name
+            });
+            this.form.findField('team_id').setFromData({
+                id: data.team_id,
+                name: data.team_id_name
+            });
+            this.form.findField('open_by').setFromData({
+                id: data.open_by,
+                name: data.open_by_name
+            });
+        }
+        this.dialog.show();
+        
+
+    },
+    save : function()
+    {
+         this.form.doAction('submit', {
+            url: baseURL + '/Roo/Projects.html',
+            method: 'POST',
+            params: {
+                _id: this._id ,
+                ts : Math.random()
+            } 
+        });
+    }
+    
+    
+    
+    
+         
+};
\ No newline at end of file
diff --git a/Pman.I18n.js b/Pman.I18n.js
new file mode 100644 (file)
index 0000000..8b92dff
--- /dev/null
@@ -0,0 +1,371 @@
+//<script type="text/javascript">
+
+
+/**
+* A few usefull tools to convert language info...
+* 
+* Our login details contain the available translation data..
+* 
+* 
+* includes standard pulldowns.
+*/
+
+Pman.I18n = {
+    
+    /**
+     * turn zh_HK,en  => into Chinese(HK) , English
+     * @arg type type (c = country, l = lang)
+     * @arg codes list of languages
+     */
+    listToNames: function (type, codes)
+    {
+        var ret = [];
+        var _this = this;
+        var cl = codes.split(',');
+        Roo.each(cl , function(c) {
+            ret.push(_this.toName(type, c));
+        });
+        return ret.join(', ');
+    },
+    /**
+     * 
+     * turns zh_HK into a Chinese(HK)
+     * @arg type type (c = country, l = lang)
+     * @arg langcode language code (eg. zh_HK, UK etc.)
+     * 
+     */
+    toName: function(type, code) 
+    {
+        var ret = code;
+        Roo.each(Pman.Login.authUser.i18n[type], function(d) {
+            if (d.code == code) {
+                ret = d.title;
+                return false;
+            }
+        });
+        return ret;
+    },
+    /**
+     * List to Objects
+     * zh_HK,en to [ { code=zh_HK, title=Chinese }, .... ]
+     * @arg type type (c = country, l = lang)
+     * @arg codes list of languages
+     */
+    listToObjects: function (type, codes)
+    {
+        var ret = [];
+        var _this = this;
+        if (!codes.length) {
+            return ret;
+        };
+        var cl = codes.split(',');
+        Roo.each(cl , function(c) {
+            ret.push({
+                code : c,
+                title : _this.toName(type,c)
+            })
+        });
+        return ret;
+    },
+    
+    
+    
+    reader :   { // std. reader for i18n items.
+        root : 'data',
+        totalProperty : 'total',
+        id : 'code',
+        xtype : 'JsonReader',
+        fields : [
+            'code',
+            'title'
+        ]
+       },
+    
+    countryStore : function() { return {
+        
+        // load using HTTP
+        xtype: 'Store',
+        proxy: {
+            xtype: 'HttpProxy',
+            url: baseURL + '/I18N/Country.html',
+            method: 'GET'
+        },
+        
+        reader: Pman.I18n.reader,
+        listeners : {
+             
+            loadexception : Pman.loadException
+
+        },
+        remoteSort: false,
+        sortInfo: {
+            field: 'title', direction: 'ASC'
+        }
+              
+    }},
+    languageStore: function() {return{
+        // load using HTTP
+        xtype: 'Store',
+        proxy: {
+            xtype: 'HttpProxy',
+            url: baseURL + '/I18N/Lang.html',
+            method: 'GET'
+        },
+        
+        reader: Pman.I18n.reader,
+        listeners : {
+             
+            loadexception : Pman.loadException
+    
+        },
+        remoteSort: false,
+        sortInfo: {
+            field: 'title', direction: 'ASC'
+        }
+    }},
+    currencyStore: function() {return{
+        // load using HTTP
+        xtype: 'Store',
+        proxy: {
+            xtype: 'HttpProxy',
+            url: baseURL + '/I18N/Currency.html',
+            method: 'GET'
+        },
+        
+        reader: Pman.I18n.reader,
+        listeners : {
+             
+            loadexception : Pman.loadException
+    
+        },
+        remoteSort: false,
+        sortInfo: {
+            field: 'title', direction: 'ASC'
+        }
+    }},
+    
+    country: function(cfg) {
+        var _this = this;
+        cfg = cfg || {};
+        return Roo.apply({
+                // things that might need chnaging
+                name : 'country_title',
+                hiddenName : 'country',
+                width : 290,
+                listWidth : 300,
+                fieldLabel : "Country",
+                allowBlank : false,
+                
+                // less likely
+                qtip : "Select Country",
+                
+                value : '',
+                // very unlinkly
+                xtype : 'ComboBox',   
+                store: this.countryStore(),
+                displayField:'title',
+                valueField : 'code',
+                typeAhead: false,
+                editable: false,
+                //mode: 'local',
+                triggerAction: 'all',
+                //emptyText:'Select a state...',
+                selectOnFocus:true 
+                 
+            }, cfg);
+    },
+    language: function(cfg) {
+               var _this = this;
+        cfg = cfg || {};
+        return Roo.apply({
+                // things that might need chnaging
+                
+                name : 'language_title',
+                hiddenName : 'language',
+                width : 290,
+                listWidth : 300,
+                fieldLabel : "Language",
+                allowBlank : false,
+                
+                // less likely
+                qtip : "Select Language",
+                
+                value : '',
+                // very unlinkly
+                xtype : 'ComboBox',   
+                store: this.languageStore(),
+                displayField:'title',
+                valueField : 'code',
+                
+                typeAhead: false,
+                editable: false,
+                //mode: 'local',
+                triggerAction: 'all',
+                //emptyText:'Select a state...',
+                selectOnFocus:true 
+                
+            }, cfg);
+    },
+       
+    currency: function(cfg) {
+        var _this = this;
+        cfg = cfg || {};
+        return Roo.apply({
+                // things that might need chnaging
+                name : 'currency_title',
+                hiddenName : 'currency',
+                width : 290,
+                listWidth : 300,
+                fieldLabel : "Currency",
+                allowBlank : false,
+                
+                // less likely
+                qtip : "Select Currency",
+                
+                value : '',
+                // very unlinkly
+                xtype : 'ComboBox',   
+                store: this.currencyStore(),
+                displayField:'code',
+                valueField : 'code',
+                typeAhead: false,
+                editable: false,
+                //mode: 'local',
+                triggerAction: 'all',
+                //emptyText:'Select a state...',
+                selectOnFocus:true,
+                   tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '{title} ({code})</b>',
+                    '</div>'
+                ) 
+                 
+            }, cfg);
+    },
+    
+    languageList : function(cfg) {
+        cfg = cfg || {};
+         
+        return Roo.apply({
+                
+                name : 'language',
+                //hiddenListName
+                fieldLabel : "Language(s)",
+                idField : 'code',
+                nameField: 'title',
+                renderer : function(d) {
+                    return String.format('{0}',  d.title );
+                },
+                
+                
+                xtype: 'ComboBoxLister',
+                displayField:'title',
+                value : '',
+               
+                qtip : "Select a language to add.",
+                selectOnFocus:true,
+                allowBlank : true,
+                width: 150,
+                boxWidth: 300,
+                 
+                store:  this.languageStore(),
+               
+                editable: false,
+                //typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all',
+                tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '{title}</b>',
+                    '</div>'
+                ),
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                listWidth: 400,
+               
+                minChars: 2,
+               // pageSize:20,
+                setList : function(ar) {
+                    var _this = this;
+                    Roo.each(ar, function(a) {
+                        _this.addItem(a);
+                    });
+                },
+                toList : function() {
+                    var ret = [];
+                    this.items.each(function(a) {
+                        ret.push(a.data);
+                    });
+                    return ret;
+                }
+                
+                 
+            }, cfg);
+    },
+    countryList : function(cfg) {
+        cfg = cfg || {};
+         
+         
+        return Roo.apply({
+                
+                name : 'countries',
+                fieldLabel : "Country(s)",
+                idField : 'code',
+                nameField: 'title',
+                renderer : function(d) {
+                    return String.format('{0}',  d.title );
+                },
+                
+                
+                xtype: 'ComboBoxLister',
+                displayField:'title',
+                value : '',
+               
+                qtip : "Select a country to add.",
+                selectOnFocus:true,
+                allowBlank : true,
+                width: 150,
+                boxWidth: 300,
+                 
+                store:  this.countryStore(), 
+               
+                editable: false,
+                //typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all',
+                tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '{title}</b>',
+                    '</div>'
+                ),
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                listWidth: 400,
+               
+                minChars: 2,
+               // pageSize:20,
+                setList : function(ar) {
+                    var _this = this;
+                    Roo.each(ar, function(a) {
+                        _this.addItem(a);
+                    });
+                },
+                toList : function() {
+                    var ret = [];
+                    this.items.each(function(a) {
+                        ret.push(a.data);
+                    });
+                    return ret;
+                }
+                
+                 
+            }, cfg);
+    }
+     
+     
+    
+};
+
+
diff --git a/Pman.Login.js b/Pman.Login.js
new file mode 100644 (file)
index 0000000..74ffefc
--- /dev/null
@@ -0,0 +1,576 @@
+//<script type="text/javascript">
+
+
+/***
+re-arrange language code...
+
+* flipping language should be like this:
+* 
+* Ext.apply(_T, _T[lang]);
+* 
+**/
+  
+
+Pman.Login =  new Roo.util.Observable({
+    
+    events : {
+        
+        'render' : true
+    },
+    disabled : false,
+    
+    dialog : false,
+    form: false,
+    haslogo : false,
+    
+    authUserId: 0,
+    authUser: { id : false },
+       
+    checkFails : 0,
+    versionWarn: false,
+    sending : false,
+    
+    onLoad : function() // called on page load...
+    {
+        // load 
+       
+         
+        if (Roo.get('loading')) {
+            Roo.get('loading').remove();
+        }
+        this.switchLang('en');
+       
+        // check if we are logged in..
+        Roo.Ajax.request({  
+            url: baseURL + '/Login.js',  
+            params: {
+                getAuthUser: true
+            },  
+            method: 'GET',  
+            success:  function(response, opts)  {  // check successfull...
+            
+                var res = Pman.processResponse(response);
+                this.checkFails =0;
+                if (!res.success) { // error!
+                    this.checkFails = 5;
+                    //console.log('call failure');
+                    return Pman.Login.failure(response,opts);
+                }
+                if (!res.data.id) { // id=0 == login failure.
+                    return this.show(true);
+                }
+                
+                              
+                        //console.log(success);
+                this.fillAuth(res.data);   
+                this.checkFails =0;
+                Pman.onload();
+            },
+            failure : Pman.Login.show,
+            scope : Pman.Login
+              
+        });  
+    }, 
+    
+    
+    check: function(again) // called every so often to refresh cookie etc..
+    {
+        if (again) { // could be undefined..
+            Pman.Login.checkFails++;
+        } else {
+            Pman.Login.checkFails = 0;
+        }
+        var _this = this;
+        if (this.sending) {
+            
+            if ( Pman.Login.checkFails > 4) {
+                Pman.Preview.disable();
+                Roo.MessageBox.alert("Error",  
+                    "Error getting authentication status. - try reloading, or wait a while", function() {
+                        _this.sending = false;
+                    }); 
+                return;
+            }
+            
+            _this.check.defer(10000, _this, [ true ]); // check in 10 secs.
+            return;
+        }
+        this.sending = true;
+        
+        Roo.Ajax.request({  
+            url: baseURL + '/Login.js',  
+            params: {
+                getAuthUser: true
+            },  
+            method: 'GET',  
+            success:  Pman.Login.success,
+            failure : Pman.Login.failure,
+            scope : Pman.Login
+              
+        });  
+    }, 
+    
+    
+    
+    failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
+    {
+        this.authUser = -1;
+        this.sending = false;
+        var res = Pman.processResponse(response);
+        //console.log(res);
+        if ( Pman.Login.checkFails > 2) {
+            Pman.Preview.disable();
+            Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg : 
+                "Error getting authentication status. - try reloading"); 
+            return;
+        }
+            
+        Pman.Login.check.defer(1000, Pman.Login, [ true ]);
+        return;  
+    },
+    
+    
+    success : function(response, opts)  // check successfull...
+    {  
+        this.sending = false;
+        var res = Pman.processResponse(response);
+        if (!res.success) {
+            return this.failure(response, opts);
+        }
+        if (!res.data || !res.data.id) {
+            return this.failure(response,opts);
+        }
+        //console.log(res);
+        this.fillAuth(res.data);
+        
+        this.checkFails =0;
+        Pman.onload();
+    },
+    
+    fillAuth: function(au) {
+        this.startAuthCheck();
+        this.authUserId = au.id;
+        this.authUser = au;
+        this.lastChecked = new Date();
+        Pman.fireEvent('authrefreshed', au);
+        //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
+        //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
+        
+        //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
+        Roo.state.Manager.set('Pman.Login.lang.'+appNameShort, au.lang);
+        this.switchLang(au.lang);
+        
+     
+        // open system... - -on setyp..
+        if (this.authUserId  < 0) {
+            Roo.MessageBox.alert("Warning", 
+                "This is an open system - please set up a admin user with a password.");  
+        }
+         
+        //Pman.onload(); // which should do nothing if it's a re-auth result...
+        
+             
+    },
+    
+    
+    intervalID : false,   /// the login refresher...
+    
+    lastChecked : false,
+    
+    startAuthCheck : function() // starter for timeout checking..
+    {
+        if (Pman.Login.intervalID) { // timer already in place...
+            return false;
+        }
+        
+        Pman.Login.intervalID =  window.setInterval(function() {
+                  Pman.Login.check(false);
+                }, 120000); // every 120 secs = 2mins..
+        
+        
+    },
+    
+    
+    create : function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        var _this = this;
+        
+        this.dialog = new Roo.LayoutDialog(Roo.get(document.body).createChild({tag:'div'}),
+        { // the real end set is here...
+            autoCreated: true,
+            title: "Login",
+            modal: true,
+            width:  350,
+            height: 230,
+            shadow:true,
+            minWidth:200,
+            minHeight:180,
+            //proxyDrag: true,
+            closable: false,
+            draggable: false,
+            collapsible: false,
+            resizable: false,
+            center: {
+                autoScroll:false,
+                titlebar: false,
+               // tabPosition: 'top',
+                hideTabs: true,
+                closeOnTab: true,
+                alwaysShowTabs: false
+            }  
+            
+        });
+        
+        
+        
+        this.dialog.addButton("Forgot Password", function()
+        {
+            
+            var n = _this.form.findField('username').getValue();
+            if (!n.length) {
+                Roo.MessageBox.alert("Error", "Fill in your email address");
+                return;
+            }
+            Roo.Ajax.request({
+                url: baseURL + '/Login.js',  
+                params: {
+                    passwordRequest: n
+                },
+                method: 'POST',  
+                success:  function(response, opts)  {  // check successfull...
+                
+                    var res = Pman.processResponse(response);
+                    if (!res.success) { // error!
+                       Roo.MessageBox.alert("Error" , res.errorMsg ? res.errorMsg  : "Problem Requesting Password Reset");
+                       return;
+                    }
+                    Roo.MessageBox.alert("Notice" , "Please check you email for the Password Reset message");
+                },
+                failure : function() {
+                    Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
+                }
+                
+            });
+        });
+        
+        this.dialog.addButton("Login", function()
+        {
+            Pman.Login.dialog.el.mask("Logging in");
+            Pman.Login.form.doAction('submit', {
+                    url: baseURL + '/Login',
+                    method: 'POST'
+            });
+        });
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+        //layout.add('center', new Roo.ContentPanel('center', {title: 'The First Tab'}));
+        // generate some other tabs
+        this.form = new Roo.form.Form({
+            labelWidth: 100 ,
+            
+            listeners : {
+                actionfailed : function(f, act) {
+                    // form can return { errors: .... }
+                        
+                    //act.result.errors // invalid form element list...
+                    //act.result.errorMsg// invalid form element list...
+                    
+                    Pman.Login.dialog.el.unmask();
+                    Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg : 
+                                "Login failed - communication error - try again.");
+                              
+                },
+                actioncomplete: function(re, act) {
+                     
+                    Roo.state.Manager.set('Pman.Login.username.'+appNameShort,  Pman.Login.form.findField('username').getValue() );
+                    Roo.state.Manager.set('Pman.Login.lang.'+appNameShort,  Pman.Login.form.findField('lang').getValue() );
+                    Pman.Login.fillAuth(act.result.data);
+                      
+                    Pman.Login.dialog.hide();
+                    if (Roo.get('loading-mask')) {
+                        //Roo.get('loading').show();
+                        Roo.get('loading-mask').show();
+                    }
+                   
+                    Pman.onload();
+                    
+                     
+                    
+                }
+            }
+        
+            
+            
+             
+        });
+          
+        
+        
+        this.form.add( 
+       
+            new Roo.form.TextField({
+                fieldLabel: "Email Address",
+                name: 'username',
+                width:200,
+                autoCreate : {tag: "input", type: "text", size: "20"}
+            }),
+
+            new Roo.form.TextField({
+                fieldLabel: "Password",
+                inputType: 'password',
+                name: 'password',
+                width:200,
+                autoCreate : {tag: "input", type: "text", size: "20"},
+                listeners : {
+                    specialkey : function(e,ev) {
+                        if (ev.keyCode == 13) {
+                            Pman.Login.dialog.el.mask("Logging in");
+                            Pman.Login.form.doAction('submit', {
+                                    url: baseURL + '/Login.json',
+                                    method: 'POST'
+                            });
+                        }
+                    }
+                }  
+            }) ,
+            new Roo.form.ComboBox({
+                fieldLabel: "Language",
+                name : 'langdisp',
+                store: {
+                    xtype : 'SimpleStore',
+                    fields: ['lang', 'ldisp'],
+                    data : [
+                        [ 'en', 'English' ],
+                        [ 'zh_HK' , '\u7E41\u4E2D' ],
+                        [ 'zh_CN', '\u7C21\u4E2D' ]
+                    ]
+                },
+                
+                valueField : 'lang',
+                hiddenName:  'lang',
+                width: 200,
+                displayField:'ldisp',
+                typeAhead: false,
+                editable: false,
+                mode: 'local',
+                triggerAction: 'all',
+                emptyText:'Select a Language...',
+                selectOnFocus:true,
+                listeners : {
+                    select :  function(cb, rec, ix) {
+                        
+                        
+                        Pman.Login.switchLang(rec.data.lang);
+                        
+                    }
+                }
+            
+            })
+
+        );
+         
+        
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+          
+        this.form.render(ef.dom);
+         // logoprefix comes from base config.
+        Pman.Login.form.el.createChild({
+                tag: 'img', 
+                src: rootURL + '/Pman/'+appNameShort + '/templates/images/logo.gif',
+                style: 'margin-bottom: 10px;'
+            },
+            Pman.Login.form.el.dom.firstChild 
+        );
+       
+        var vp = this.dialog.getLayout().add('center', new Roo.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+        
+        this.layout.endUpdate();
+        
+        this.fireEvent('render', this);
+        
+        
+        
+        
+        
+    },
+    resizeToLogo : function()
+    {
+        var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
+        if (!sz) {
+            this.resizeToLogo.defer(1000,this);
+            return;
+        }
+        var w = Ext.lib.Dom.getViewWidth() - 100;
+        var h = Ext.lib.Dom.getViewHeight() - 100;
+        Pman.Login.dialog.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
+        Pman.Login.dialog.center();
+    },
+    
+     
+    
+    show: function (modal) 
+    {
+        if (this.disabled) {
+            return;
+        }
+        modal = modal || false;
+        if (Pman.Login.authUserId < 0) { // logout!?
+            return;
+        }
+        
+        if (Pman.Login.intervalID) {
+            // remove the timer
+            window.clearInterval(Pman.Login.intervalID);
+            Pman.Login.intervalID = false;
+        }
+        
+        this.create();
+        
+        
+        
+        if (Roo.get('loading')) {
+            Roo.get('loading').remove();
+        }
+        if (Roo.get('loading-mask')) {
+            Roo.get('loading-mask').hide();
+        }
+        
+        //incomming._node = tnode;
+        this.form.reset();
+        this.dialog.modal = !modal;
+        this.dialog.show();
+        this.dialog.el.unmask(); 
+        this.resizeToLogo.defer(1000,this);
+        
+         
+        this.form.setValues({
+            'username' : Roo.state.Manager.get('Pman.Login.username.'+appNameShort, ''),
+            'lang' : Roo.state.Manager.get('Pman.Login.lang.'+appNameShort, 'en')
+        });
+        Pman.Login.switchLang(Roo.state.Manager.get('Pman.Login.lang.'+appNameShort, ''));
+        if (this.form.findField('username').getValue().length > 0 ){
+            this.form.findField('password').focus();
+        } else {
+           this.form.findField('username').focus();
+        }
+        
+        
+    },
+    
+     
+    logout: function()
+    {
+        window.onbeforeunload = function() { }; // false does not work for IE..
+        Pman.Login.authUserId = -1;
+        Roo.Ajax.request({  
+            url: baseURL + '/Login.html',  
+            params: {
+                logout: 1
+            },  
+            method: 'GET',
+            failure : function() {
+                Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
+                    document.location = baseURL + '?ts=' + Math.random();
+                });
+                
+            },
+            success : function() {
+                Pman.Login.authUserId = -1;
+                Pman.Login.checkFails =0;
+                // remove the 
+                document.location = baseURL + '?ts=' + Math.random();
+            }
+              
+              
+        }); 
+    },
+    switchLang : function (lang) {
+        if (!lang.length) {
+            return;
+        }
+        if (typeof(_T.en) == 'undefined') {
+            _T.en = {};
+            Roo.apply(_T.en, _T);
+        }
+        
+        if (typeof(_T[lang]) == 'undefined') {
+            Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
+            return;
+        }
+        
+        
+        Roo.apply(_T, _T[lang]);
+        // just need to set the text values for everything...
+        if (this.form) {
+            
+               
+            function formLabel(name, val) {
+                
+                var lbl = Pman.Login.form.findField( name ).el.dom.parentNode.parentNode;
+                if (lbl.getElementsByTagName('label').length) {
+                    lbl = lbl.getElementsByTagName('label')[0];
+                } else  {
+                    lbl = lbl.parentNode.getElementsByTagName('label')[0];
+                }
+                   
+                lbl.innerHTML = val;
+            }
+            
+            formLabel('password', "Password"+':');
+            formLabel('username', "Email Address"+':');
+            formLabel('lang', "Language"+':');
+            this.dialog.setTitle("Login");
+            this.dialog.buttons[0].setText("Forgot Password");
+            this.dialog.buttons[1].setText("Login");
+        }
+        
+        
+    },
+    
+    inGroup : function(g)
+    {
+        return this.authUser && this.authUser.groups && 
+            this.authUser.groups.indexOf(g) > -1;
+    },
+    isOwner : function()
+    {
+        return this.authUser && this.authUser.company_id_comptype && 
+            this.authUser.company_id_comptype == 'OWNER';
+    },
+    
+    /**
+     * Depreciated = use Pman.I18n
+     */
+    
+    i18nList: function (type, codes)
+    {
+        
+        return Pman.I18n.listToNames(type, codes);
+    },
+    i18n: function(type, code) 
+    {
+        return Pman.I18n.toName(type, code);
+        
+    }
+    
+    
+});
+
+
+
+
+   
diff --git a/Pman.PasswordChange.js b/Pman.PasswordChange.js
new file mode 100644 (file)
index 0000000..5171c78
--- /dev/null
@@ -0,0 +1,193 @@
+//<script type="text/javascript">
+Pman.PasswordChange = {
+    
+    
+     
+    dialog : false,
+    form : false,
+    create: function()
+    {
+        if (this.dialog) {
+            return;
+        }
+        var _this = this;
+        
+        
+        this.dialog = new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:'div'}),  { 
+            autoCreated: true,
+            title: "Change Password",
+            modal: true,
+            width:  500,
+            height: 160,
+            shadow:true,
+            resizable: false,
+            closable: false,
+            draggable: false,
+            center: {
+                autoScroll:false,
+                titlebar: false,
+               // tabPosition: 'top',
+                hideTabs: true,
+                closeOnTab: true,
+                alwaysShowTabs: false
+            }
+            
+            
+        });
+        var dgcloser = function(data) {
+            Pman.Preview.tmpEnable();
+            
+            _this.dialog.hide();
+            if (_this.callback) {
+                _this.callback.call(this, data ? data : false);
+            }
+        };
+        
+        this.dialog.addKeyListener(27, dgcloser,this);
+        this.dialog.addButton("Cancel",dgcloser,this);
+        this.dialog.addButton("Save", this.save, this);
+        
+        
+        this.layout = this.dialog.getLayout();
+        this.layout.beginUpdate();
+        
+        
+        this.form = new Ext.form.Form({
+            labelWidth: 220 ,
+            
+            listeners : {
+                actionfailed : function(f, act) {
+                    //console.log(act);
+                    _this.dialog.el.unmask();
+                    // error msg???
+                    
+                    if (act.failureType == 'client') {
+                        Ext.MessageBox.alert("Error", "Please Correct all the errors");
+                        return;
+                        
+                    }
+                    
+                    if (act.type == 'submit') {
+                        
+                        Ext.MessageBox.alert("Error", typeof(act.result.errorMsg) == 'string' ?
+                            act.result.errorMsg : 
+                            "Saving failed = fix errors and try again");
+                        return;
+                    }
+                    
+                    // what about load failing..
+                    Ext.MessageBox.alert("Error", "Error loading details"); 
+                              
+                },
+                actioncomplete: function(f, act) {
+                    _this.dialog.el.unmask();
+                    
+                    if (act.type == 'submit') { // only submitted here if we are 
+                        dgcloser(act.data);
+                        return; 
+                    }
+                    // unmask?? 
+                }
+            }
+        
+            
+            
+             
+        });
+        //?? will this work...
+        this.form.addxtype.apply(this.form,[
+            {
+                name : 'passwd1',
+                fieldLabel : "New Password ",
+                value : '',
+                allowBlank : false, // must be filled in as we rely on it for login details..
+                inputType: 'password',
+                xtype : 'SecurePass',
+                width : 220,
+                imageRoot : rootURL + '/Pman/templates/images'
+            },
+            {
+                
+                name : 'passwd2',
+                fieldLabel : "New Password (type again to confirm)",
+                value : '',
+                allowBlank : false, // must be filled in as we rely on it for login details..
+                inputType: 'password',
+                xtype : 'TextField',
+                width : 220
+            },
+             
+            {
+                name : 'passwordReset',
+                value : '',
+                xtype : 'Hidden'
+                
+            }
+        ]);
+        
+        
+         
+        
+        var ef = this.dialog.getLayout().getEl().createChild({tag: 'div'});
+        ef.dom.style.margin = 10;
+         
+        this.form.render(ef.dom);
+
+        var vp = this.dialog.getLayout().add('center', new Ext.ContentPanel(ef, {
+            autoCreate : true,
+            //title: 'Org Details',
+            //toolbar: this.tb,
+            width: 250,
+            maxWidth: 250,
+            fitToFrame:true
+        }));
+         
+         
+        
+        this.layout.endUpdate();
+    },
+    _id : 0,
+    show : function(data, callback)
+    {
+        this.callback= callback;
+        this.data = data;
+        this.create();
+        this.form.reset();
+         
+        // edit...
+        this.form.setValues(data);
+        
+        Pman.Preview.tmpDisable();
+        
+        this.dialog.show();
+        this.form.findField('passwd1').focus();
+        
+    },
+    save : function()
+    {
+        var p1 = this.form.findField('passwd1').getValue();
+        var p2 = this.form.findField('passwd2').getValue();
+        if (!p1.length || !p2.length) {
+            Ext.MessageBox.alert("Error", "Enter Passwords in both boxes");
+        }
+        if (p1 != p2) {
+            Ext.MessageBox.alert("Error", "Passwords do not match");
+        }
+        
+        this.form.doAction('submit', {
+            url: baseURL + '/Login.html',
+            method: 'POST',
+            params: {
+                changePassword: true,
+                ts : Math.random()
+            } 
+        });
+    }
+     
+      
+    
+    
+}
\ No newline at end of file
diff --git a/Pman.Preview.js b/Pman.Preview.js
new file mode 100644 (file)
index 0000000..edf5305
--- /dev/null
@@ -0,0 +1,333 @@
+//<script type="text/javascript">
+
+/**
+ * 
+ * singleton preview frame / object..
+ * 
+ * -- has two objects
+ * -- frame and obj
+ * frame = handles doc's that can appear in frames
+ * pdf = is for firefox - displaying PDF's and others????
+ * 
+ */
+
+Pman.Preview = {
+    
+    frame  : false,
+    pdf : false,
+    imgDiv : false,
+    active: false, // frame of pdf
+    init : function()
+    {
+
+        if (this.frame) { // already exists.
+            return; 
+        }
+        
+         
+        //var frm = this.layout.getEl().createChild({
+        //        tag:'iframe', 
+        //        src: 'about:blank'});
+        if (Roo.isGecko) {
+            this.pdf = Ext.DomHelper.append(
+                document.body,
+                {
+                    id : 'pdf-view',
+                    tag: 'object', 
+                    type : 'application/pdf',
+                    data : 'about:blank',
+                    width : 200,
+                    height :200,
+                    style : 'position:absolute;top:-1000;left:-1000; z-index:-100',
+                    cn : [ 
+                        {
+                            tag: 'param',
+                            name : 'src',
+                            value : 'about:blank'
+                        }
+                    ]
+                },
+                false
+            );
+             
+        }
+        this.imgDiv =  Ext.DomHelper.append(
+                document.body,
+                { 
+                    tag:'div', 
+                    style : 'position:absolute;top:-1000;left:-1000; z-index:-100;' + 
+                        'overflow-x:hidden;overflow-y:scroll;width:200px; height: 200px;' 
+                }
+        );
+            
+        this.frame =  Ext.DomHelper.append(
+                document.body,
+                { 
+                    tag:'iframe', 
+                    src: 'about:blank',
+                    style : 'position:absolute;top:-1000;left:-1000; z-index:-100;' + 
+                        'width:1px; height: 1px;'
+                }
+        );
+        
+    },
+    config : false,
+    
+    
+    onResize : function() 
+    {
+        if (this.active ) {
+            this.active.style.zIndex = this.activeCfg ? this.activeCfg.zIndex : -100;
+        }
+        
+        //var pz = this.config.previewRegion.panelSize;
+        //if (!pz) {
+        //    return;
+        //   }
+        //if (pz.width < 10) {
+        //    return;
+        //}
+        if (!this.config.previewRegion) {
+            return;
+        }
+        
+        
+        
+        var pos = this.config.previewRegion.el.getBox();
+        if (pos.width < 10) {
+            return;
+        }
+        
+        
+        //var top = pos.y + (pos.height - pz.height);
+        if (!this.active) {
+            return;
+        }
+        
+        this.active.setAttribute( 'width',pos.width);             
+        this.active.setAttribute( 'height',pos.height); 
+        //if (!Ext.isIE) {
+            this.active.style.width = pos.width + 'px';
+            this.active.style.height = pos.height + 'px';
+        //}
+        
+        this.active.style.top = pos.y + 'px';
+        this.active.style.left = pos.x + 'px';
+        
+        /*
+        this.active.setAttribute( 'width',pz.width);             
+        this.active.setAttribute( 'height',pz.height); 
+        //if (!Ext.isIE) {
+            this.active.style.width = pz.width + 'px';
+            this.active.style.height = pz.height + 'px';
+        //}
+        
+        this.active.style.top = top + 'px';
+        this.active.style.left = pos.x + 'px';
+        */
+    },
+        
+     
+    
+    unlink: function ()
+    {
+        // remove the listeners on that object...
+        if (!this.config) {
+            return;
+        }
+        if (this.config.dialog ) {
+            this.config.dialog.un('hide', this.onHide, this);
+        }
+         if (this.config.tab) {
+            this.config.tab.un('deactivate', this.onHide, this);
+        }
+        this.config.previewRegion.un('resized', this.onResize, this);
+       // this.config.previewRegion.getSplitBar().un('beforeresize', this.disable, this);
+        this.config = false;
+    },
+    
+    link: function(config)
+    {
+        // add the listener to the ownerDiv..
+       
+        this.init();
+        if (this.config) {
+            this.unlink();
+        }
+        this.config = config;
+        if (this.config.dialog) {
+            this.config.dialog.on('hide', this.onHide, this);
+        }
+        if (this.config.tab) {
+            this.config.tab.on('deactivate', this.onHide, this);
+        }
+        
+        this.config.previewRegion.on('resized', this.onResize, this);
+        //this.config.previewRegion.getSplitBar().on('beforeresize', this.disable, this);
+    },
+    
+     
+    removeActive: function() 
+    {
+        if (!this.active) {
+            return;
+        }
+        this.active.style.left='-1000px';
+        this.active.style.top='-1000px';
+        this.active.style.width='200px';
+        this.active.style.top='200px';
+        this.active.style.zIndex= -100;
+        this.active = false;
+    },
+    
+    onHide: function () {
+        if (!this.active) {
+            return;
+        }
+        this.removeActive();
+        this.unlink();
+    },
+    
+    showPdf : function()
+    {
+        this.removeActive();
+        this.activeCfg.url = this.activeCfg.pdfurl;
+        this.activeCfg.mimetype = 'application/pdf';
+        this.load(this.activeCfg);
+    },
+    
+    /**
+     * 
+     * config args
+     * url: load url
+     * mimetype : load mimetype (needs more explaination)
+     * pdfurl : 
+     * width : (for image)
+     * height:  (for image)
+     * 
+     */
+    load : function(cfg)
+    {
+        
+        this.activeCfg = false;
+        if (typeof(cfg) != 'object') {
+            alert('Preview Load only accepts object with url/mimetype/zIndex as loader');
+            return;
+        }
+        this.activeCfg = Roo.apply({},cfg);
+        var    url = this.activeCfg.url;
+        var    mimetype = this.activeCfg.mimetype;
+        
+        this.removeActive();
+        //this.enable();
+        
+        switch (mimetype) {
+            
+            case 'image/jpeg': // preview!!!!
+                // we need to show this in a floating div...
+                //var ps  = 100; //this.config.previewRegion.panelSize;
+                var ps = this.config.previewRegion.el.getBox();
+                
+                this.imgDiv.innerHTML = '<img src="' + url +'"' + 
+                    ' width="'+ (ps.width-15) + '"' +
+                    ' qtip="'+ "Click to view PDF" + '"' +
+                    ' ext:width="100"' +
+                      ' onclick="Pman.Preview.showPdf();"/>';
+                this.active = this.imgDiv;
+                this.enable(this.activeCfg.zIndex);
+                return;
+                break;
+            
+            
+            case 'application/pdf':
+            case 'application/msword':
+            case 'application/vnd.oasis.opendocument.text':
+           
+            case 'application/vnd.ms-excel':
+            case 'application/vnd.oasis.opendocument.spreadsheet':
+            case 'application/vnd.dwg':
+            case 'application/acad':
+            case 'application/x-acad':
+            case 'application/autocad_dwg':
+            case 'image/x-dwg':
+            case 'application/dwg':
+            case 'application/x-dwg':
+            case 'application/x-autocad':
+            case 'image/vnd.dwg':
+            case 'drawing/dwg':
+                
+                if (!url.match(/\.pdf$/)) {
+                    url += '.pdf';
+                }
+                
+                if (!Roo.isGecko) {
+                  
+                    this.frame.src = url;
+                    this.active = this.frame;
+                    this.enable(this.activeCfg.zIndex);
+                    return;
+                }
+                this.pdf.setAttribute( 'data',  url);
+               // this.pdf.childNodes[0].setAttribute( 'src',  url);
+                this.active = this.pdf;
+                this.enable(this.activeCfg.zIndex);
+                return;
+                
+            default:
+                this.frame.src =   url; ///'about:blank';
+                this.active = this.frame;
+                this.enable(this.activeCfg.zIndex);
+                return;
+                
+            
+        }
+         
+        
+    },
+    disable: function()
+    {
+        
+        if (!this.active) {
+            return;
+        }
+        this.disabled = true;
+        this.active.style.zIndex = -100;
+         if (!Roo.isGecko) {
+            this.frame.src= 'about:blank';
+         }
+    },
+    enable: function(zIndex)
+    {
+        if (!this.active) {
+            return;
+        }
+        this.disabled = false;
+        
+        this.active.style.zIndex = zIndex ? zIndex : 10000;
+         if (!Roo.isGecko && this.activeCfg) {
+            this.frame.src= this.activeCfg.url;
+         }
+        
+        this.onResize();
+    },
+    tmpStatus : false,
+    tmpDisable : function()
+    {
+        if (this.disabled) {
+            this.tmpStatus = false;
+            return;
+        }
+        this.tmpStatus = true;
+        this.disable();
+    },
+    tmpEnable: function()
+    {
+        if (!this.tmpStatus) {
+            return;
+        }
+        this.tmpStatus = false;
+        this.enable();
+    }
+    
+    
+}
\ No newline at end of file
diff --git a/Pman.Remarks.js b/Pman.Remarks.js
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Pman.Std.js b/Pman.Std.js
new file mode 100644 (file)
index 0000000..75ce610
--- /dev/null
@@ -0,0 +1,362 @@
+//<script type="text/javascript">
+
+/**
+* 
+* All Our standard form fields
+* 
+* should move this really..
+* 
+*/
+
+Pman.Std = {
+    project_id : function (cfg) {
+        cfg = cfg || {};
+        cfg.storeListeners = cfg.storeListeners || {};
+        return  Roo.apply({
+                
+            width: 200,
+            fieldLabel: "Project",
+            name : 'project_id_code',
+            hiddenName:  'project_id',
+            
+            allowBlank : false,
+            selectOnFocus:true,
+            qtip : "Select Project",
+            
+            
+            
+            xtype: 'ComboBox',
+            
+            store: {
+                xtype : 'Store',
+                  // load using HTTP
+                proxy: {
+                    xtype : 'HttpProxy',
+                    url: baseURL + '/Roo/Projects.html',
+                    method: 'GET'
+                },
+                reader: Pman.Readers.Projects,
+                listeners : Roo.apply(
+                    {
+                        loadexception : Pman.loadException
+                    }, 
+                    cfg.storeListeners
+                ),
+                remoteSort : true,
+                sortInfo: {
+                    field: 'code', direction: 'ASC'
+                }
+            },
+            displayField:'code',
+            valueField : 'id',
+            
+            typeAhead: true,
+            forceSelection: true,
+            //mode: 'local',
+            triggerAction: 'all',
+            tpl: new Ext.Template(
+                '<div class="x-grid-cell-text x-btn button">',
+                    '<b>{code}</b> {name}',
+                '</div>'
+            ),
+            queryParam: 'query[project_search]',
+            loadingText: "Searching...",
+            listWidth: 400,
+           
+            minChars: 2,
+            pageSize:20 
+             
+        }, cfg);
+   },
+   
+    
+   company_id : function(cfg) { // really picks names...
+        cfg = cfg || {};
+        cfg.storeListeners = cfg.storeListeners || {};
+        // we may want to set up cfg listners default here???
+        cfg.listeners = cfg.listeners || {};
+           
+        return Roo.apply({
+                // things we might want to change...
+                
+                name : 'addressto_name',
+                displayField:'name',
+                
+                fieldLabel : "Sent To",
+                allowBlank : true,
+                qtip : "Enter Sent To",
+                width: 290,
+                
+                
+                value : '',
+                xtype: 'ComboBoxAdder',
+                selectOnFocus:true,
+                allowBlank : false,
+                
+               
+                store: {
+                      // load using HTTP
+                    xtype: 'Store',
+                    proxy: {
+                        xtype : 'HttpProxy',
+                        url: baseURL + '/Roo/Companies.html',
+                        method: 'GET'
+                    },
+                    reader: Pman.Readers.Companies,
+                    
+                    listeners : Roo.apply(
+                        {
+                            loadexception : Pman.loadException
+                        }, 
+                        cfg.storeListeners
+                    ),
+                    remoteSort : true,
+                    sortInfo: {
+                        field: 'name', direction: 'ASC'
+                    }
+                    
+                },
+              
+                typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all',
+                tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '<b>{name}</b> {address}',
+                    '</div>'
+                ),
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                listWidth: 400,
+               
+                minChars: 2,
+                pageSize:20 
+                
+            }, cfg);
+    },
+    
+    doctype_name: function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+                // things that might need chnaging
+                name : 'doctype_name',
+                width : 290,
+                fieldLabel : "Type",
+                allowBlank : false,
+                
+                // less likely
+                qtip : "Select Document Type",
+                
+                value : '',
+                // very unlinkly
+                xtype : 'ComboBox',   
+                store: {
+                    // load using HTTP
+                    xtype: 'Store',
+                    proxy: {
+                        xtype: 'HttpProxy',
+                        url: baseURL + '/Roo/Document_Types.html',
+                        method: 'GET'
+                    },
+                    
+                    reader: Pman.Readers.Document_Types,
+                    listeners : {
+                        beforeload: function(t, o) {
+                            //console.log(o.params);
+                            o.params.limit = 9999;
+                        },
+                        loadexception : Pman.loadException
+                
+                    },
+                    remoteSort: true,
+                    sortInfo: {
+                        field: 'name', direction: 'ASC'
+                    }
+                },
+                displayField:'name',
+                
+                typeAhead: false,
+                editable: false,
+                //mode: 'local',
+                triggerAction: 'all',
+                //emptyText:'Select a state...',
+                selectOnFocus:true 
+            }, cfg);
+    },
+    
+    
+    address_list_adder : function(cfg) {
+        cfg = cfg || {};
+        cfg.storeListeners = cfg.storeListeners || {};
+        return Roo.apply({
+                
+                name : 'send_to',
+                fieldLabel : "To",
+                idField : 'email',
+                
+                 renderer : function(d) {
+                    return String.format('{0}', 
+                        d.name.length ? d.name : d.email
+                    );
+                },
+                
+                
+                xtype: 'ComboBoxLister',
+                displayField:'name',
+                value : '',
+               
+                qtip : "Select an address to add.",
+                selectOnFocus:true,
+                allowBlank : true,
+                width: 150,
+                
+                
+                store: {
+                    xtype : 'Store',
+                      // load using HTTP
+                    proxy: {
+                        xtype : 'HttpProxy',
+                        url: baseURL + '/Roo/Person.html',
+                        method: 'GET'
+                    },
+                    reader: Pman.Readers.Companies,
+                    listeners : cfg.storeListeners, 
+                    remoteSort : true,
+                    sortInfo: {
+                        field: 'name', direction: 'ASC'
+                    }
+                },
+               
+                
+                typeAhead: true,
+                forceSelection: true,
+                //mode: 'local',
+                triggerAction: 'all',
+                tpl: new Ext.Template(
+                    '<div class="x-grid-cell-text x-btn button">',
+                        '<b>{name}</b> {email}',
+                    '</div>'
+                ),
+                queryParam: 'query[name]',
+                loadingText: "Searching...",
+                listWidth: 400,
+               
+                minChars: 2,
+                pageSize:20,
+                setList : function(ar) {
+                    var _this = this;
+                    Roo.each(ar, function(a) {
+                        _this.addItem(a);
+                    });
+                },
+                toList : function() {
+                    var ret = [];
+                    this.items.each(function(a) {
+                        ret.push(a.data);
+                    });
+                    return ret;
+                }
+                
+                 
+            }, cfg);
+    },
+    
+    
+    our_office_id : function(cfg) 
+    {
+        cfg = cfg || {};
+        cfg.listeners = cfg.listeners  || {};
+        return Roo.apply({
+            xtype: 'ComboBoxAdder',
+            fieldLabel: "Office / Department",
+            
+            hiddenName:  'office_id',
+            name : 'office_id_name',
+            
+            qtip : "Select Office",
+            width: 300,
+            allowBlank : true,
+            triggerAction: 'all',
+            
+            
+            typeAhead: true,
+            forceSelection: true,
+            selectOnFocus:true,
+            
+            displayField:'name',
+            valueField : 'id',
+            
+            store:  {
+                xtype : 'Store',
+                  // load using HTTP
+                proxy: {
+                    xtype : 'HttpProxy',
+                    url: baseURL + '/Roo/Office.html',
+                    method: 'GET'
+                },
+                reader: Pman.Readers.Office,
+                listeners : Roo.apply({
+                    loadexception : Pman.loadException
+                    }, cfg.storeListeners
+                ),
+                remoteSort : true,
+                sortInfo: {
+                    field: 'name', direction: 'ASC'
+                }
+            },
+            listeners : Roo.apply({
+                adderclick : function()
+                {
+                     
+                    var ncfg = {
+                        company_id : Pman.Login.authUser.company_id * 1,
+                        company_id_name:  Pman.Login.authUser.company_id_name,
+                        address: '',
+                        phone: '',
+                        fax: '',
+                        email: ''
+                    };
+
+                    
+                    Pman.Preview.tmpDisable();
+                    
+                    Pman.Dialog.Office.show(ncfg, function(data) {
+                        _this.setFromData(data);
+                        Pman.Preview.tmpEnable();
+                    }); 
+                } 
+            }, cfg.listeners),
+           
+            //mode: 'local',
+            
+            tpl: new Ext.Template(
+                '<div class="x-grid-cell-text x-btn button">',
+                    '<b>{name}</b> {address}',
+                '</div>'
+            ),
+            queryParam: 'query[name]',
+            loadingText: "Searching...",
+            listWidth: 400,
+           
+            minChars: 2,
+            pageSize:20 
+             
+             
+             
+        }, cfg);
+    },
+    
+    /**
+     * Depreciated - use Pman.I18n directly
+     * 
+     */
+
+    country: function(cfg) { return Pman.I18n.country(cfg); }, 
+    language: function(cfg) { return Pman.I18n.language(cfg); }, 
+       
+    languageList : function(cfg) { return Pman.I18n.languageList(cfg); },
+    countryList : function(cfg) { return Pman.I18n.countryList(cfg); }
+     
+        
+};
\ No newline at end of file
diff --git a/Pman.Tab.GroupsList.js b/Pman.Tab.GroupsList.js
new file mode 100644 (file)
index 0000000..bf91aa8
--- /dev/null
@@ -0,0 +1,377 @@
+
+//<script type="text/javascript">
+
+// generic groups listing tab
+
+
+Pman.Tab.GroupsList = function(config) {
+    Ext.apply(this, config);
+};
+
+Pman.Tab.GroupsList.prototype = {
+    id : false,
+    grid : false,
+    panel : false,
+    getDialog : false,
+    title : false,
+    type : 0,
+    disabled : false,
+    add : function(parentLayout, region) {
+        
+        var _this = this;
+        
+        var refreshPager = function() {
+            _this.refresh();
+        }
+        
+        if (this.panel) {
+            parentLayout.getRegion(region).showPanel(this.panel);
+            return;
+        }
+          
+        var refreshCenterPanel = function()
+        {
+            var actpan = parentLayout.getRegion('center').getActivePanel();
+            if (actpan && actpan.controller) {
+                actpan.controller.refresh();
+                return;
+            }
+            // depreciated..
+            var agid = actpan.id;
+            if (!agid) {
+                return;
+            }
+            Pman.Tab[agid].refresh();
+        }
+        
+        var frm = parentLayout.getRegion(region).getEl().createChild({tag:'div'});
+        //this.grid = new Ext.grid.EditorGrid(frm,  {
+        this.grid = new Ext.grid.Grid(frm,  {
+                id: _this.id + '-groups',
+                
+                //enableDragDrop:true,
+                enableDrop:true,
+                ddGroup: 'groupDD',
+                
+                //dropConfig: {
+                //    appendOnly : true,
+                //    ddGroup: 'groupDD' 
+                //},
+                ds:   new Ext.data.Store({
+                    // load using HTTP
+                    
+                    
+                    proxy: new Ext.data.HttpProxy({
+                        url: baseURL + '/Roo/Groups.html',
+                        method: 'GET'
+                    }),
+                    remoteSort: true,
+                    reader: Pman.Readers.Groups,
+                    sortInfo: {
+                        field: 'name', direction: 'ASC'
+                    },
+                    listeners : {
+                        
+                        beforeload: function(t, o) {
+                            //console.log(o.params);
+                            if (!o.params) {
+                                o.params = {};
+                            }
+                            o.params.type = _this.type;
+                            
+                            
+                        },
+                        load : function()
+                        {
+                            var sm = _this.grid.getSelectionModel();
+                            if (!sm.getSelections().length) {
+                                sm.selectFirstRow();
+                            }
+                            refreshCenterPanel();
+                          //  Pman.Tab.Documents_In.delayedCreate();
+                          //  Pman.Tab.Documents_Out.delayedCreate();
+                        },
+                        loadexception : Pman.loadException
+                    
+                    }
+                }),
+                sm: new Ext.grid.RowSelectionModel({ singleSelect: true }),
+                cm: new Ext.grid.ColumnModel(
+                    [{
+                        id : _this.id + '-name',
+                        header : "Name",
+                        dataIndex : 'name',
+                        sortable : true,
+                        width : 100,
+                        renderer : function(v,x,r) {
+                            if (r.data.id == -1) {
+                                return '<b>' + "Not in a Group" + '</b>';
+                            }
+                            if ((r.data.id == 0) && (_this.type == 0)) {
+                                return '<b>' + "All Staff (Default Permissions)" + '</b>';
+                            }
+                            if ((r.data.id == 0) && (_this.type == 2)) {
+                                return '<b>' + "Everybody" + '</b>';
+                            }
+                            if (r.data.id == 0) {
+                                return '<b>' + "All Staff" + '</b>';
+                            }
+                            if (v == 'Administrators') {
+                                return '<b>' + "Adminstrators" + '</b>';
+                            }
+                            if (r.data.leader) {
+                                return v + ' (' + r.data.leader_name + ')';
+                            }
+                            
+                            return v;
+                            /*
+                            switch (v) {
+                                case 'Default':
+                                    return '<b>' + "All Staff (Default Perms.)" + '</b>';
+                                case 'Administrators':
+                                    return '<b>' + "Administrators" + '</b>';
+                                default: 
+                                    return v;
+                            }
+                            */
+                            
+                       }
+                    }]
+                ),
+                autoExpandColumn: _this.id + '-name' , // fixme!!!!
+                clicksToEdit : 1,
+                
+                loadMask: true,
+                listeners : {
+                    rowclick: function(g, ri, e)
+                    {
+                        refreshCenterPanel();
+                    } 
+                }
+                 
+        });
+        // add selection changed...
+        
+        this.panel  = parentLayout.add(region,  new Ext.GridPanel(this.grid ,
+            { fitToframe: true,fitContainer: true, title: _this.title, id : _this.id, background: true})
+        );
+        this.grid.render();
+        
+        
+        new Ext.dd.DropTarget(_this.grid.getView().mainBody, {  
+            ddGroup : 'groupDD',  
+            copy       : true,
+
+            notifyOver : function(dd, e, data){  
+                var t = Roo.lib.Event.getTarget(e); 
+                var ri = _this.grid.view.findRowIndex(t);
+                var rid  = false;
+                if (ri !== false) {
+                    rid = _this.grid.getDataSource().getAt(ri).data;
+                }
+                
+                var s = _this.grid.getSelectionModel().getSelections();
+                
+                var isFromGroup = s.length ? s[0].data.id > 0 : false;
+                
+                var isToGroup = rid && rid.id > 0;
+                
+                if (isFromGroup && isToGroup) {
+                    return this.dropNotAllowed; 
+                }
+                if (!isFromGroup && !isToGroup) {
+                    return this.dropNotAllowed; 
+                }
+                if (isFromGroup && !isToGroup) {
+                    return 'x-dd-drop-ok-sub'; 
+                } 
+                //if (!isFromGroup && isToGroup) {
+                    return 'x-dd-drop-ok-add'; 
+                //}
+                
+                  
+            },  
+            notifyDrop : function(dd, e, data){  
+                
+                var t = Roo.lib.Event.getTarget(e); 
+                var ri = _this.grid.view.findRowIndex(t);
+                var rid  = false;
+                if (ri !== false) {
+                    rid = _this.grid.getDataSource().getAt(ri).data;
+                }
+                var s = _this.grid.getSelectionModel().getSelections();
+                  
+                //console.log(data);
+                var isFromGroup = s.length ? s[0].data.id > 0 : false;
+                
+                var isToGroup = rid && rid.id > 0;
+                
+                if (isFromGroup && isToGroup) {
+                    return false;
+                }
+                if (!isFromGroup && !isToGroup) {
+                    return false;
+                }
+                var action = 'add';
+                if (isFromGroup && !isToGroup) {
+                    action = 'sub';
+                    //return 'x-dd-drop-ok-sub'; 
+                }
+                // build a list of selections.
+                var sels = [];
+                for (var i=0; i < data.selections.length; i++) {
+                    sels.push(data.selections[i].data.id);
+                }
+                
+                Pman.request({
+                    url: baseURL + '/Core/GroupMembers.php',
+                    params: {
+                        action : action,
+                        group_id: action =='add' ? rid.id : s[0].data.id,
+                        type: _this.type,
+                        user_ids : sels.join(',')
+                        
+                    },  
+                    method: 'POST',  
+                    success : function(data) {
+                        refreshPager();
+                    }, 
+                    
+                    failure: function() {
+                        //Ext.get(document.body).unmask();
+                        //if (cb) {
+                        //    cb.call(false);
+                        //}
+                         
+                    }
+                });
+                
+                
+                
+                //if (!isFromGroup && isToGroup) {
+                    //return 'x-dd-drop-ok-add'; 
+                return true;
+                //}
+                
+                  
+            }
+        });  
+        
+        /*
+        var gridFoot = this.grid.getView().getFooterPanel(true);
+        
+        this.paging = new Ext.PagingToolbar(gridFoot, this.grid.getDataSource(), {
+            pageSize: 25,
+            displayInfo: true,
+            displayMsg: '',
+            emptyMsg: ''
+        });
+        */
+        var grid = this.grid;
+        var gridHead = this.grid.getView().getHeaderPanel(true);
+        this.toolbar = new Ext.Toolbar(gridHead);
+          
+        var _dialog= this.getDialog();
+        this.toolbar.add({
+            
+            text: "Manage Groups",
+            cls: 'x-btn-text-icon',
+            icon: Ext.rootURL + 'images/default/tree/leaf.gif',
+            menu : {
+                items : [
+                    
+                    {
+                        text: "Add",
+                         cls: 'x-btn-text-icon',
+                        icon: Ext.rootURL + 'images/default/dd/drop-add.gif',
+                        hidden : !Pman.hasPerm('Core.Groups', 'A'),
+                        handler : function(){
+                            _dialog.show( { id : 0, type: _this.type }, refreshPager ); 
+                        }
+                    }, 
+                    {
+                        text: "Edit",
+                        cls: 'x-btn-text-icon',
+                        icon: Ext.rootURL + 'images/default/tree/leaf.gif',
+                        hidden : !Pman.hasPerm('Core.Groups', 'E'),
+                        handler : function() {
+                            var s = grid.getSelectionModel().getSelections();
+                            if (!s.length || (s.length > 1))  {
+                                Ext.MessageBox.alert("Error", s.length ? "Select only one Row" : "Select a Row");
+                                return;
+                            }
+                            if ((s[0].data.name == 'Administrators') ||(s[0].data.name == 'Default')) {
+                                Ext.MessageBox.alert("Error", "You can not rename that group");
+                                return;
+                            }
+                            if (s.data.id < 1) {
+                                Ext.MessageBox.alert("Error", "You can not rename that group");
+                                return;
+                            }
+                            _dialog.show(s[0].data, refreshPager); 
+                        }
+                    },  
+                    
+                    {
+                        text: "Delete",
+                         cls: 'x-btn-text-icon',
+                        icon: rootURL + '/Pman/templates/images/trash.gif',
+                        hidden : !Pman.hasPerm('Core.Groups', 'D'),
+                        handler : function(){
+                            var s = grid.getSelectionModel().getSelections();
+                              
+                            for(var i = 0; i < s.length; i++) {
+                                
+                                if ((s[i].data.id < 1) || (s[i].data.name == 'Administrators')) {
+                                    Ext.MessageBox.alert("Error", "You can not delete that group");
+                                    return;
+                                }
+                            }
+                            
+                            
+                            Pman.genericDelete(_this, 'Groups'); 
+                        } 
+                    } , '-',
+                      {
+                        text: "Reload",
+                         cls: 'x-btn-text-icon',
+                           icon: rootURL + '/Pman/templates/images/view-refresh.gif',
+                        handler : function(){
+                            refreshPager();
+                        }
+                    }
+                ]
+            }
+                    
+        });
+        this.panel.on('activate', function() {
+           // refreshPager();
+        });
+            
+        //this.toolbar = tb;
+        // add stuff to toolbar?
+        //this.innerLayout.endUpdate();
+        
+        
+        
+    },
+    refresh: function()
+    {
+        this.grid.getDataSource().reload();   
+    } /*,
+   // - is this used anymore? 
+   
+    show: function (parentLayout, region)
+    {
+        this.add(parentLayout, region);
+        this.grid.getDataSource().load({
+            params: {
+                type: _this.type
+            }
+        });
+
+    }
+    */
+};
diff --git a/Pman.Tab.PersonList.js b/Pman.Tab.PersonList.js
new file mode 100644 (file)
index 0000000..43298e7
--- /dev/null
@@ -0,0 +1,598 @@
+//<script type="text/javascript">
+
+/**
+ * 
+ * generic person list - used by perms. and staff lists.
+ * 
+ */
+
+
+
+Pman.Tab.PersonList = function(config)
+{
+    Ext.apply(this, config);
+}
+
+Pman.Tab.PersonList.prototype = {
+    
+    //--- things that should be set!!!!
+    id : '',  // should be set to something!
+    type : 0, // means!! = 0 = Groups (perms) 1= teams - loose grouping..
+    title : false,
+    hiddenColumns: false,  // lsit of cols to hide..
+    itemDisplayName : false, /// eg "Staff Employees / Contacts etc."
+    permName : 'Core.Person', // or 'Core.Staff'
+    getLeftSelections : function() { return []; },
+    hideDelete : false,
+    
+    // beforeload handler... -- override on extended versions..
+    beforeload: function(t, o) {
+        //console.log(o.params);
+        // teams!?!
+        alert('person list not configured');
+        return false;
+        var tms = _this.getLeftSelections();
+        
+        if (tms.length) {
+            o.params['query[in_group]'] = tms[0].data.id;
+        }
+        o.params['query[name]'] = this.searchBox.getValue();
+        o.params['query[type]'] = this.type; // group type..
+        o.params['query[person_internal_only_all]'] = 1;
+        o.params['query[person_inactive]'] = this.showInActive ? 0  : 1;
+        
+    },
+    
+    columns : function()
+    {
+        alert('person list not configured');
+        return false;
+        return [
+            this.c_name(),
+            this.c_office_id_name(),
+            this.c_role(),
+            this.c_phone(),
+            this.c_fax(),
+            this.c_email(),
+            this.c_active()
+        ]
+    },
+    
+    dialog: function () {
+        alert('person list not configured');
+        return false;
+        return Pman.Dialog.PersonStaff;
+    },
+    bulkAdd : function() {
+        //return Pman.Dialog.PersonBulkAdd
+        return false;
+    },
+    newDefaults : function() {
+        alert('person list not configured');
+        return false;
+        return {
+            
+            id : 0,
+            company_id : Pman.Login.authUser.company_id,
+            company_id_name : Pman.Login.authUser.company_id_name,
+            company_id_address : Pman.Login.authUser.company_id_address,
+            company_id_tel : Pman.Login.authUser.company_id_tel,
+            company_id_fax : Pman.Login.authUser.company_id_fax
+        };
+    },
+         
+    
+    
+    /// --- end extendable bits...
+    
+    
+    parentLayout : false,
+    showInActive : 0,  // toggle var for hiding and showing active staff..
+    grid : false,
+    panel : false,
+    toolbar : false,
+    paging:  false,
+    tab: false,
+    
+    
+    refreshWestPanel : function() /// used wher???
+    {
+        var actpan = this.parentLayout.getRegion('west').getActivePanel();
+        if (actpan && actpan.controller) {
+            actpan.controller.paging.onClick('refresh');
+            return;
+        }
+        // depreciated..    
+    
+        if (!actpan || !actpan.id) {
+            return;
+        }
+        Pman.Tab[actpan.id].refresh();
+    },
+    
+    refresh: function(){
+        if (!this.paging) {
+            this.delayedCreate();
+        }
+        this.paging.onClick('refresh');
+    },
+    
+    loadFirst: function(){
+        if (!this.paging) {
+            this.delayedCreate();
+        }
+        this.paging.onClick('first');
+    },  
+    
+    
+    
+    add : function(parentLayout, region) {
+        
+        var _this = this;
+        if (this.tab) {
+            parentLayout.getRegion(region).showPanel(this.panel);
+            return;
+        }
+        this.parentLayout = parentLayout;
+        
+        this.layout = new Ext.BorderLayout(
+            parentLayout.getEl().createChild({tag:'div'}),
+            {
+               
+                center: {
+                    autoScroll:true,
+                    hideTabs: true
+                }
+            }
+        );
+
+
+
+        this.tab = parentLayout.add(region,  new Ext.NestedLayoutPanel(
+            this.layout, {title: this.title, background: true, controller : this}));
+
+        this.tab.on('activate', function() {
+            _this.delayedCreate();
+           // _this.paging.onClick('refresh');
+        });
+    },
+    delayedCreate : function () 
+     
+    {
+        var _this = this;
+        if (this.grid) {
+            return;
+        }
+        
+        var refreshPager = function() {
+            _this.refresh();
+        }
+        this.layout.beginUpdate();
+        
+        var frm = this.layout.getRegion('center').getEl().createChild({tag:'div'});
+        //this.grid = new Ext.grid.EditorGrid(frm,  {
+        this.grid = new Ext.grid.Grid(frm,  {
+                ddGroup: 'groupDD',
+                //enableDrag: true,
+                enableDrag: true,
+                id: this.id + '-grid',
+                ds:   new Ext.data.Store({
+                    // load using HTTP
+                    proxy: new Ext.data.HttpProxy({
+                        url: baseURL + '/Roo/Person.html',
+                        method: 'GET'
+                    }),
+                    reader: Pman.Readers.Person,
+                    remoteSort: true,
+                    listeners : {
+                        
+                        beforeload: function(t, o) {
+                            //console.log(o.params);
+                            // teams!?!
+                            return _this.beforeload(t,o);
+                             
+                            
+                        },
+                        loadexception : Pman.loadException
+                    
+                    },
+                    sortInfo: {
+                        field: 'name', direction: 'ASC'
+                    }
+                }),
+                cm: new Ext.grid.ColumnModel(
+                    this.columns()
+                ),
+                autoExpandColumn: _this.id + '-name' , // fixme!!!!
+                clicksToEdit : 1,
+                
+                loadMask: true,
+
+                listeners : {
+                    rowdblclick : function(g, ri, e) {
+                        var s = g.getDataSource().getAt(ri).data;
+                        if (_this.dialog() && Pman.hasPerm(_this.permName, 'E')) {
+                            _this.dialog().show(s,refreshPager);
+                        }
+                        
+                        
+                    } 
+                    
+                }
+                 
+                 
+        });
+        this.panel  = this.layout.add('center',  new Ext.GridPanel(this.grid , {
+                fitToframe: true,
+                fitContainer: true, 
+                id: this.id, 
+                title: this.title || "Staff", 
+                controller : this 
+            })
+        );
+        this.grid.render();
+        
+        if (this.hiddenColumns) {
+            var cm = this.grid.getColumnModel();
+            Roo.each(this.hiddenColumns, function(c) {
+                cm.setHidden(cm.getIndexByDataIndex(c), true);
+            });
+        }
+        
+
+        
+        var gridFoot = this.grid.getView().getFooterPanel(true);
+        this.paging = new Ext.PagingToolbar(gridFoot, this.grid.getDataSource(), {
+            pageSize: 25,
+            displayInfo: true,
+            displayMsg: "Displaying " + (this.itemDisplayName || "Staff") + " {0} - {1} of {2}",
+            emptyMsg: "No " + (this.itemDisplayName || "Staff") + " found"
+        });
+        var grid = this.grid;
+    
+        this.toolbar = new Ext.Toolbar(this.grid.getView().getHeaderPanel(true));
+        
+        var tb = this.toolbar;
+        
+        
+        if (this.parentLayout.getRegion('west') && this.parentLayout.getRegion('west').panels.length) {
+                
+            this.paging.add( 
+                '<b><i><font color="red">'+ 
+                    (this.type ?
+                        "Drag person to add or remove from group" :
+                        "Drag person to add or remove from team"
+                    ) +
+                '</font></i></b>'
+            );
+        }
+        
+        var _this = this;
+        if (this.permName == 'Core.Staff') {
+                
+            this.paging.add( '-',
+                {
+                    text: "Show old staff",
+                    pressed: false,
+                    enableToggle: true,
+                    toggleHandler: function(btn,pressed) {
+                        _this.showInActive = (pressed ? 1 : 0);
+                        btn.setText(pressed ? "Hide old staff": "Show old staff" );
+                        refreshPager();
+                    }
+                }, 
+                
+               
+                '-'
+            );
+        }
+        
+     
+        this.searchBox = new Ext.form.TextField({
+            name: 'search',
+            width:135,
+            listeners : {
+                specialkey : function(f,e)
+                {
+                    
+                    if (e.getKey() == 13) {
+                        
+                        refreshPager();
+                    } 
+                   
+                
+                }
+            }
+         
+        });
+        var dg = _this.dialog();
+        tb.add(
+            {
+                text: "Add",
+                cls: 'x-btn-text-icon',
+                icon: Ext.rootURL + 'images/default/dd/drop-add.gif',
+                hidden :  !dg || (_this.newDefaults() === false) || !Pman.hasPerm(this.permName, 'A'),  
+                handler : function(){
+                    dg.show(  _this.newDefaults(), refreshPager );  
+                }
+            }, 
+             { ///... for contacts stuff...
+                text: "Bulk Add",
+                cls: 'x-btn-text-icon',
+                icon: Ext.rootURL + 'images/default/dd/drop-add.gif',
+                hidden : !this.bulkAdd() || !Pman.hasPerm(this.permName, 'A'),    
+                handler : function(){
+                    
+                   // Pman.Dialog.PersonBulkAdd.show( {  id : 0 }, refreshPager ); 
+                   _this.bulkAdd().show( {  id : 0 }, refreshPager ); 
+                }
+            },
+
+            {
+                text: "Edit",
+                cls: 'x-btn-text-icon',
+                icon: Ext.rootURL + 'images/default/tree/leaf.gif',
+                hidden : !dg || !Pman.hasPerm(this.permName, 'E'),    
+                handler : function(){
+                    var s = grid.getSelectionModel().getSelections();
+                    if (!s.length || (s.length > 1))  {
+                        Ext.MessageBox.alert("Error", s.length ? "Select only one Row" : "Select a Row");
+                        return;
+                    }
+                    dg.show( s[0].data,refreshPager);
+                 }
+            }, 
+            {
+                text: "Toogle Active",
+                cls: 'x-btn-text-icon',
+                icon:   rootURL + '/Pman/templates/images/trash.gif',
+                hidden : (this.permName != 'Core.Staff') || !Pman.hasPerm(this.permName, 'E'),   // SPECIFIC TO STAFF!!!!!!
+                handler : function(){
+                 
+                    var s = grid.getSelectionModel().getSelections();
+                    if (!s.length  )  {
+                        Ext.MessageBox.alert("Error",  "Select People Row");
+                        return;
+                    }
+                    var r = [];
+                    for(var i = 0; i < s.length; i++) {
+                        r.push(s[i].data.id);
+                    }
+                
+                
+                
+                    grid.getView().mainWrap.mask("Sending");
+
+                    
+                    Ext.Ajax.request({
+                        url: baseURL + '/Roo/Person.html',
+                        method: 'GET',
+                        params: {
+                            _toggleActive : r.join(',')
+                        },
+                        success: function(resp) {
+                            var res = Pman.processResponse(resp);
+                            grid.getView().mainWrap.unmask();
+                            if (!res.success) {
+                                Ext.MessageBox.alert("Error", res.errorMsg ? res.errorMsg  : "Error Sending");
+                                return;
+                            }
+                            refreshPager();
+                            
+                        },
+                        failure: function(act) {
+                            grid.getView().mainWrap.unmask();
+                            Ext.MessageBox.alert("Error", "Error Sending");
+                        }
+                        
+                    });
+                }
+                
+            }, 
+            {
+                text: "Delete",
+                cls: 'x-btn-text-icon',
+                hidden : (this.permName == 'Core.Staff') ||  !Pman.hasPerm('Core.Person', 'D') || this.hideDelete,    
+                icon: rootURL + '/Pman/templates/images/trash.gif',
+                handler : function(){
+                    Pman.genericDelete(_this, 'Person'); 
+                }
+            } ,
+
+           
+            '-',
+            'Search: ',
+             
+            this.searchBox,
+        
+            {
+                
+               
+                icon: rootURL + '/Pman/templates/images/search.gif', // icons can also be specified inline
+                cls: 'x-btn-icon',
+                qtip: "Search",
+                handler : function () { 
+                    _this.grid.getSelectionModel().clearSelections();
+
+                    refreshPager();
+                }
+            },   
+             {
+                
+               
+                icon: rootURL + '/Pman/templates/images/edit-clear.gif', // icons can also be specified inline
+                cls: 'x-btn-icon',
+                qtip: "Reset Search",
+                handler : function () {
+                    _this.searchBox.setValue('');
+                    _this.grid.getSelectionModel().clearSelections();
+
+                    refreshPager();
+                }
+            }
+            
+
+        );
+        
+            
+        //this.toolbar = tb;
+        // add stuff to toolbar?
+        //this.innerLayout.endUpdate();
+         this.layout.endUpdate();
+
+        
+        
+    },
+    /*
+    show: function (parentLayout, region)
+    {
+        this.add(parentLayout, region);
+        this.grid.getDataSource().load({
+            params: {
+                start:0, 
+                limit:25
+            }
+        });
+
+    },
+    */
+    
+    c_project_id_code : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({               
+            header : "Project",
+            dataIndex : 'project_id_code',
+            sortable : false,
+            width : 70,
+            renderer : function(v,x,r) {
+                return String.format('<span qtip="{0}">{1}</span>', 
+                    r.data.action_type,
+                    v);
+            }
+        },cfg);
+    },
+
+    
+    
+    
+    c_name : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            id : this.id + '-name',
+            header : "Name",
+            dataIndex : 'name',
+            sortable : true,
+            width : 150  
+        }, cfg);
+    },
+     c_company_id_comptype : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Company Type",
+            dataIndex : 'company_id_comptype',
+            sortable : true,
+            width : 70
+        }, cfg);
+    },
+    
+    c_company_id_name : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Company / Office",
+            dataIndex : 'company_id_name',
+            sortable : true,
+            width : 150,
+            renderer: function(v,x,r) {
+                return String.format('{0}{1}{2}', 
+                    v,
+                    r.data.office_id ? ' / ' : '',
+                    r.data.office_id_name);
+            }
+
+        }, cfg);
+    },
+    
+    c_office_id_name : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Office / Dept.",
+            dataIndex : 'office_id_name',
+            sortable : true,
+            width : 150  
+        }, cfg);
+        
+    },
+    c_role : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Role / Position",
+            dataIndex : 'role',
+            sortable : true,
+            width : 100
+        }, cfg);
+        
+    },
+    c_phone : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Phone",
+            dataIndex : 'phone',
+            sortable : true,
+            width : 70
+        }, cfg);
+        
+    },
+    c_fax : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Fax",
+            dataIndex : 'fax',
+            sortable : true,
+            width : 70
+        }, cfg);
+        
+    },
+    c_email : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Email",
+            dataIndex : 'email',
+            sortable : true,
+            width : 150,
+            renderer : function (v) {
+                return (v.length && v.indexOf('@') > 0 ) ? 
+                    String.format('<a href="mailto:{0}">{0}</a>',v) : v;
+            }
+        }, cfg);
+        
+    },
+    c_active : function(cfg) {
+        cfg = cfg || {};
+        return Roo.apply({
+            header : "Active",
+            dataIndex : 'active',
+            sortable : true,
+            width : 50,
+            renderer : function(v) {
+                // work out what the column is..
+                
+                var state = v> 0 ?  '-checked' : '';
+
+                return '<img class="x-grid-check-icon' + state + '" src="' + Ext.BLANK_IMAGE_URL + '"/>';
+                
+                
+            }
+
+        }, cfg);
+        
+    }
+     
+    
+    
+};
+// need two version of this 
+// (one can be used as edit + ProjectDirectory ADD)
+// - the other one needs selection combos's for company / office
+
+
diff --git a/Pman.js b/Pman.js
new file mode 100644 (file)
index 0000000..039d761
--- /dev/null
+++ b/Pman.js
@@ -0,0 +1,961 @@
+//<script type="text/javascript">
+
+/**
+ * 
+ * >>> Pman.layout.getRegion('center').tabs.stripWrap
+ * ==> tab.???
+ * var tbh = Pman.layout.getRegion('center').tabs.stripWrap.child('div').createChild(
+ * 
+ * {tag: 'div', style: 'display:block;position:absolute;top:2;left:300;width:100%;height:25px'});
+ * 
+ */
+if (typeof(_T) == 'undefined') { _T={};}
+
+  
+
+Pman = new Roo.Document(
+{
+   /// appVersion: '1.7', // fixme = needs to be removed - use Global AppVersion
+    subMenuItems : [],
+    topMenuItems : [],
+    rightNames: { }, /// register right names here - so they can be translated and rendered.
+    buildCompleted : false, // flag to say if we are building interface..
+    events : {
+        'beforeload' : true, // fired after page ready, before module building.
+        'load' : true, // fired after module building
+        'authrefreshed' : true // fire on auth updated?? - should be on Login?!?!?
+    },
+    
+    listeners : {
+        'ready' : function()
+        {
+            // kludge to fix firebug debugger
+            if (typeof(console) == 'undefined') {
+                console = { log : function() {  } };
+            }
+            
+            // remove loader..
+            if (Ext.get('loading')) {
+                Ext.get('loading').remove();
+            }
+            
+            Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
+            
+            // link errors...
+            
+            if (AppLinkError.length) {
+                Ext.MessageBox.alert("Error", AppLinkError, function() {
+                    Pman.Login.onLoad();
+                });
+                return;
+            }
+            
+            
+            // reset password!!!!
+            if (showNewPass.length) {
+                Pman.PasswordChange.show(  { passwordReset : showNewPass },
+                    function(data) {
+                        // fail and success we do  a load...
+                        Pman.Login.onLoad();
+                    }
+                );
+                return;
+            }
+             
+            Pman.Login.onLoad();
+            
+        },
+        'load' : function()
+        {
+            if (Roo.get('loading-logo-tile')) {
+                Roo.get('loading-logo-tile').remove();
+            }
+            if (Roo.get('loading-logo-tile-top')) {
+                Roo.get('loading-logo-tile-top').remove();
+            }
+            if (Roo.get('loading-logo-bottom')) {
+                Roo.get('loading-logo-bottom').remove();
+            }
+            if (Roo.get('loading-logo-center')) {
+                Roo.get('loading-logo-center').remove();
+            }
+        }   
+        
+    },
+   
+
+    
+    layout: false,
+    
+    onload: function() {
+        //this.fireEvent('beforeload',this);
+        
+        
+        
+        if (this.layout) {
+            return; // already loaded
+        } 
+        if (Ext.get('loading')) {
+            Ext.get('loading').remove();
+        }
+        if (Ext.get('loading-mask')) {
+            Ext.get('loading-mask').show();
+        }
+        
+        
+       
+        
+        /*
+        Ext.MessageBox.show({
+           title: "Please wait...",
+           msg: "Building Interface...",
+           width:340,
+           progress:true,
+           closable:false
+          
+        });
+        */
+        //Pman.onLoadBuild();
+        //Ext.get(document.body).mask("Building Interface");
+        //Pman.onLoadBuild.defer(100, Pman);
+       //Pman.onLoadBuild();
+                    
+   // },
+    //onLoadBuild : function() {
+        
+        var _this = this;
+        this.stime = new Date();
+        this.layout = new Ext.BorderLayout(document.body, {
+            north: {
+                split:false,
+                initialSize: 25,
+                titlebar: false
+            },
+         
+             
+            center: {
+                titlebar: false,
+                autoScroll:false,
+                closeOnTab: true,
+                tabPosition: 'top',
+                //resizeTabs: true,
+                alwaysShowTabs: true,
+                minTabWidth: 140
+            } /*,
+            south: {
+                split:false,
+                initialSize: 25,
+                titlebar: false
+            }
+            */
+        });
+        
+        this.fireEvent('beforeload',this);
+        
+        
+        
+        this.layout.beginUpdate();
+        this.layout.add('north', new Ext.ContentPanel('title', 'North'));
+        var au = Pman.Login.authUser;
+        if (au.id > 0 && au.company_id_background_color.length) {
+            Ext.get('title').dom.style.backgroundColor = '#' + au.company_id_background_color;
+            Ext.get('headerInformation').dom.style.color = this.invertColor('#' + au.company_id_background_color);
+        }
+        if (au.id > 0 && au.company_id_logo_id * 1 > 0) {
+            Ext.get('headerInformation-company-logo').dom.src =  baseURL + 
+                '/Images/' + au.company_id_logo_id + '/' + au.company_id_logo_id_filename;
+        } else {
+            Ext.get('headerInformation-company-logo').dom.src = Roo.BLANK_IMAGE_URL;
+        }
+        
+        Ext.get('headerInformation').dom.innerHTML = String.format(
+                "You are Logged in as <b>{0} ({1})</b>", // to {4} v{3}", // for <b>{2}</b>",
+                au.name, au.email, au.company_id_name, 
+                AppVersion , appNameShort
+        );
+        
+        
+        document.title = appName + ' v' + AppVersion + ' - ' + au.company_id_name;
+        Ext.QuickTips.init(); 
+        if (Ext.isGecko) {
+           Ext.useShims = true;
+        }
+       
+        //this.mainLayout.beginUpdate();
+        //var maskDom = Ext.get(document.body)._maskMsg.dom
+        this.layout.beginUpdate();
+        
+        Pman.building = true;
+        
+        this.buildModules(this, 
+            function() {
+                
+                _this.layout.getRegion('center').showPanel(0);
+                _this.layout.endUpdate(); 
+                _this.addTopToolbar();  
+                _this.finalize();
+                _this.fireEvent('load',this);
+            }
+        );
+        
+        
+     
+    },
+    
+    addTopToolbar : function()
+    {
+          //console.log( "t6:" + ((new Date())-stime));
+        //this.mainLayout.endUpdate();
+        // make a new tab to hold administration stuff...
+        
+       
+        //console.log( "t7:" + ((new Date())-stime));
+        var se = Pman.layout.getRegion('center').tabs.stripEl;
+        var tbh = se.createChild( 
+                { tag: 'td', style: 'width:100%;'  });
+        
+        var lotb = new Ext.Toolbar(tbh);
+        
+        if (Roo.isSafari) {
+            var tbl = se.child('table', true);
+            tbl.setAttribute('width', '100%');
+        }
+        lotb.add(
+            new Ext.Toolbar.Fill(), 
+     
+            {
+                text: "Change Password",
+                cls: 'x-btn-text-icon',
+                icon: rootURL + '/Pman/templates/images/change-password.gif',
+                handler : function(){
+                    Pman.PasswordChange.show({});
+                }
+            }, '-'
+        );
+         
+        
+        if (this.topMenuItems.length) {
+            
+            Roo.each(this.topMenuItems, function (mi) {
+                lotb.add(mi);
+            });
+            lotb.add('-');
+        }
+        
+        
+        
+        if (this.subMenuItems.length) {
+            
+            this.subMenuItems.sort(function (a,b) {
+                return a.seqid > b.seqid ? 1 : -1;
+            });
+            // chop off last seperator.
+            // since we always add it.. just chop of last item
+            this.subMenuItems.pop(); 
+            
+            lotb.add(
+                {
+                     
+                    text: "Add New Item",
+                    cls: 'x-btn-text-icon',
+                    icon: Ext.rootURL + 'images/default/dd/drop-add.gif',
+                    menu : {
+                        items : this.subMenuItems
+                    }     
+                } ,'-'
+            );
+        }
+       
+        lotb.add(
+            {
+                text: "Logout",
+                cls: 'x-btn-text-icon',
+                icon: rootURL + '/Pman/templates/images/logout.gif',
+                handler: function() {
+                    Pman.Login.logout();
+                }
+                 
+            }
+        );
+      
+       // this.layout.endUpdate();
+    },
+    
+    
+    finalize : function() {
+        
+      
+       
+        window.onbeforeunload = function(e) { 
+            var e = e || window.event;
+            var r = "Closing this window will loose changes, are you sure you want to do that?";
+
+            // For IE and Firefox
+            if (e) {
+                e.returnValue = r;
+            }
+
+            // For Safari
+            return r;
+            
+        };
+        
+        Ext.MessageBox.hide();
+        if (Ext.get('loading-mask')) {
+           Ext.get('loading-mask').remove();
+        }
+        
+        
+        this.buildCompleted = true; // now we can force refreshes on everything..
+        
+        
+        // does the URL indicate we want to see a system..
+        if (AppTrackOnLoad * 1 > 0) {
+            this.onLoadTrack(AppTrackOnLoad,false);
+        }
+        
+        // Open system..
+        
+        var forceAdmin = function(data)
+        {
+            if (!data || !data.id) {
+                Pman.Dialog.PersonStaff.show( 
+                    { 
+                        id : 0, 
+                        company_id : Pman.Login.authUser.company_id * 1, 
+                        company_id_name : Pman.Login.authUser.company_id_name
+                    }, function(data) {
+                        forceAdmin(data);
+                    }
+                );
+                return;
+            }
+            Ext.state.Manager.set('Pman.Login.username', data.email),
+            window.onbeforeunload = false;
+            document.location = baseURL + '?ts=' + Math.random();
+        }
+        
+        var forceCompany = function(data) {
+            if (Pman.Login.authUser.company_id * 1 > 0) {
+                forceAdmin();
+                return;
+            }
+            if (!data || !data.id) {
+                Pman.Dialog.Companies.show( { id : 0, isOwner : 1, comptype: 'OWNER' }, function(data) {
+                    forceCompany(data);
+                });
+                return;
+            }
+            Pman.Login.authUser.company_id  = data.id;
+            Pman.Login.authUser.company_id_name  = data.name;
+            forceAdmin();
+        }
+        
+        if (Pman.Login.authUser.id < 0) {
+            forceCompany();
+            /// create account..
+            
+            
+        }
+        
+
+    },
+    
+    
+    
+    
+     
+    onLoadTrack : function(id,cb) {
+        this.onLoadTrackCall(id, cb, 'DocumentsCirc_');
+    },
+    onLoadTrackEdit : function(id,cb) {
+        this.onLoadTrackCall(id, cb, 'Documents_');
+    },
+    
+    
+    /// ----------- FIXME -----
+    
+    
+    onLoadTrackCall : function(id,cb, cls) {
+        Ext.get(document.body).mask("Loading Document details");
+
+        Pman.request({
+            url: baseURL + '/Roo/Documents.html',  
+            params: {
+                _id: id
+            },  
+            method: 'GET',  
+            success : function(data) {
+                Ext.get(document.body).unmask();
+             
+                
+                switch(data.in_out) {
+                    case 'IN' : cls+='In';break;
+                    case 'OUT' : cls+='Out';break;
+                    case 'WIP' : cls+='Wip';break;
+                    default: 
+                        Ext.MessageBox.alert("Error", "invalid in_out");
+                        return;
+                }
+                Pman.Dialog[cls].show(data, cb ? cb : Pman.refreshActivePanel);
+            }, 
+            
+            failure: function() {
+                Ext.get(document.body).unmask();
+                //if (cb) {
+                //    cb.call(false);
+                //}
+                 
+           }
+        });
+          
+    },
+    
+    /**
+     * eg. has Pman.hasPerm('Admin.Admin_Tab', 'S') == showlist..
+     * 
+     */
+    hasPerm: function(name, lvl) {
+        if (typeof(Pman.Login.authUser) != 'object') {
+            return false;
+        }
+        if (typeof(Pman.Login.authUser.perms[name]) != 'string') {
+            return false;
+        }
+        return Pman.Login.authUser.perms[name].indexOf(lvl) > -1;
+        
+    },
+    
+    
+    
+    
+    
+    
+    
+    
+    Readers : {},
+    ColModels : {},
+    Forms : {},
+    Tab : {},
+    Dialog : {},
+    
+    processResponse : function (response)
+    {
+        var res = '';
+        try {
+            res = Ext.decode(response.responseText);
+            // oops...
+            if (typeof(res) != 'object') {
+                res = { success : false, errorMsg : res, errors : true };
+            }
+            if (typeof(res.success) == 'undefined') {
+                res.success = false;
+            }
+            
+        } catch(e) {
+            res = { success : false,  errorMsg : response.responseText, errors : true };
+        }
+        return res;
+    },
+    genericDelete : function(tab,tbl) {
+        
+        var r = [];
+        
+            
+        var s = tab.grid.getSelectionModel().getSelections();
+        if (!s.length)  {
+            Ext.MessageBox.alert("Error", "Select at least one Row to delete" );
+            return '';
+        }
+        
+        for(var i = 0; i < s.length; i++) {
+            r.push(s[i].data.id);
+        }
+    
+        Ext.MessageBox.confirm("Confirm", "Are you sure you want to delete that?",
+            function(btn) {
+                if (btn != 'yes') {
+                    return;
+                }
+                // what about the toolbar??
+                tab.grid.getView().mainWrap.mask("Deleting");
+                Pman.request({
+                    url: baseURL + '/Roo/'+tbl+'.php',
+                    method: 'GET',
+                    params: {
+                        _delete : r.join(',')
+                    },
+                    success: function(response) {
+                        tab.grid.getView().mainWrap.unmask();
+                        if ( tab.paging ) {
+                            tab.paging.onClick('refresh');   
+                        } else if (tab.refresh) {
+                            tab.refresh();
+                        } else if (tab.grid.footer && tab.grid.footer.onClick) {
+                            // new xtype built grids
+                            tab.grid.footer.onClick('refresh');   
+                        } else {
+                            tab.grid.getDataSource().load();
+                        }
+                        
+                        
+                        
+                    },
+                    failure: function(act) {
+                        tab.grid.getView().mainWrap.unmask();
+                        Ext.MessageBox.alert("Error", "Error Deleting");
+                    }
+                    
+                });
+            }
+        );
+    },
+    refreshActivePanel : function() {
+        var actpan = this.layout.getRegion('center').getActivePanel();
+        if (actpan.controller && actpan.controller.paging) {
+            actpan.controller.paging.onClick('refresh');
+            return;
+        }
+        
+        var agid = Pman.layout.getRegion('center').getActivePanel().id;
+        if (!agid) {
+            return;
+        }
+        Pman.Tab[agid].paging.onClick('refresh');
+    },
+    toCidV : function(data) {
+        return 'C' + data.in_out.substring(0,1) + data.cid;
+    },
+    
+    standardActionFailed :  function(f, act, cb) {
+    
+        if (act.failureType == 'client') {
+            Ext.MessageBox.alert("Error", "Please Correct all the errors in red", cb);
+            return;
+        }
+        if (act.failureType == 'connect') {
+            Ext.MessageBox.alert("Error", "Problem Connecting to Server - please try again.", cb);
+            return;
+        }
+        
+        if (act.type == 'submit') {
+            
+            Ext.MessageBox.alert("Error", typeof(act.result.errorMsg) == 'string' ?
+                String.format('{0}', act.result.errorMsg) : 
+                "Saving failed = fix errors and try again", cb);
+            return;
+        }
+        
+        // what about load failing..
+        Ext.MessageBox.alert("Error", "Error loading details",cb); 
+    },
+    /**
+     * 
+     * similar to Ext.Ajax, but handles our responses better...
+     * c.url
+     * c.method
+     * c.params
+     * c.failure() == failure function..
+     * c.success(data) == success function..
+     * 
+     * 
+     */
+    request : function(c) {
+        
+        Ext.Ajax.request({
+            timeout : c.timeout || 30000,
+            url: c.url,
+            method : c.method,
+            params: c.params,
+            xmlData : c.xmlData,
+            success:  function(response, opts)  {  // check successfull...
+               
+                var res = Pman.processResponse(response);
+                
+                if (!res.success) { // error!
+                    if (c.failure) {
+                        if (true === c.failure.call(this,response, opts)) {
+                            return;
+                        }
+                    }
+                    Roo.MessageBox.hide();
+                    Ext.MessageBox.alert("Error", res.errorMsg ? res.errorMsg : "Error Sending");
+                    return;
+                }
+                
+                c.success.call(this, res.data);
+                
+                return; 
+            },
+            failure :  function(response, opts)  {  // check successfull...
+                
+                if (c.failure) {
+                    if (true === c.failure.call(this,response, opts)) {
+                        return;
+                    }
+                }
+                Roo.MessageBox.hide();
+                Roo.MessageBox.alert("Error", "Connection timed out sending");
+                console.log(response);
+                
+            },
+            scope: this
+            
+        });
+    },
+    csvFrame : false,
+    
+    createCsvFrame: function()
+    {
+        
+        if (this.csvFrame) {
+            document.body.removeChild(this.csvFrame);
+        }
+            
+        var id = Ext.id();
+        this.csvFrame = document.createElement('iframe');
+        this.csvFrame.id = id;
+        this.csvFrame.name = id;
+        this.csvFrame.className = 'x-hidden';
+        if(Ext.isIE){
+            this.csvFrame.src = Ext.SSL_SECURE_URL;
+        }
+        document.body.appendChild(this.csvFrame);
+
+        if(Ext.isIE){
+            document.frames[id].name = id;
+        }
+        
+    },
+    /**
+     * download({
+          url: 
+         })
+     * 
+     * 
+     */
+    
+    
+    download : function(c) {
+        
+        if (c.newWindow) {
+            // as ie seems buggy...
+            window.open( c.url + '?' + Roo.urlEncode(c.params || {}), '_blank');
+            return;
+            
+        }
+        
+        this.createCsvFrame();
+        function cb(){
+            var r = { responseText : "", responseXML : null };
+
+            var frame = this.csvFrame;
+
+            try { 
+                var doc = Ext.isIE ? 
+                    frame.contentWindow.document : 
+                    (frame.contentDocument || window.frames[this.csvFrame.id].document);
+                
+                if(doc && doc.body && doc.body.innerHTML.length){
+                  //  alert(doc.body.innerHTML);
+                    Ext.MessageBox.alert("Error download",doc.body.innerHTML);
+                }
+                 
+            }
+            catch(e) {
+            }
+
+            Ext.EventManager.removeListener(frame, 'load', cb, this);
+        }
+        Ext.EventManager.on( this.csvFrame, 'load', cb, this);
+        this.csvFrame.src = c.url;
+    },
+    downloadRevision : function(doc, rev)
+    {
+        this.download({
+            url: baseURL + '/Documents/Doc/DownloadRev/'+ doc.id + '/' + rev + '/' +
+                doc.project_id_code + '-' + doc.cidV + '-' + rev  + '-' +  doc.filename
+        }); 
+                    
+    },
+    exportCSV : function(c) {
+        //this.createCsvFrame(); 
+        for(var i=0;i < c.csvFormat.length;i++) {
+            c.params['csvCols['+i+']'] = c.csvFormat[i][0];
+            c.params['csvTitles['+i+']'] = c.csvFormat[i][1];
+        }
+        
+        
+        c.url +=  '?' + Ext.urlEncode(c.params);
+        this.download(c);
+
+    },
+    prettyDate : function (value) 
+    {
+        if (typeof(value) == 'string') {
+            var ds = Date.parseDate(value, 'Y-m-d H:i:s');
+            if (ds) {
+                return this.prettyDate(ds);
+            }
+            ds = Date.parseDate(value, 'Y-m-d');
+            if (ds) {
+                return this.prettyDate(ds);
+            }
+            return '';
+        }
+// last 7 days...
+        if (!value) {
+            return '';
+        }
+        var td = new Date();
+        var daysSince = Math.floor(td.getElapsed(value) / (1000 * 60*60*24));
+        if (daysSince < 7) {
+            return value.dateFormat('D H:i');
+        }
+        
+        // same month
+        if (td.dateFormat('m') == value.dateFormat('m')) {
+            return value.dateFormat('dS D');
+        }
+        // same year?
+        if (td.dateFormat('Y') == value.dateFormat('Y')) {
+            return value.dateFormat('dS M');
+        }
+        return value.dateFormat('d M Y');
+    },
+    loadException : function(a,b,c,d)
+    {
+        if (d && d.authFailure) {
+            Pman.Login.show();
+            return;
+        }
+        Roo.MessageBox.alert("Problem Loading Data", a.message || c.statusText);
+    },
+    
+    
+    /**
+     * 
+     * Routine to flash alerts in the title bar..
+     * 
+     * 
+     */
+    
+    notifyActive : false,
+    
+    notifyTitle: function(msg)
+    {
+        if (this.notifyActive ) {
+            return;
+        }
+        var stop = false;
+        
+        var stopper = function() {
+            stop = true;
+             document.title = oldtitle;
+        };
+        
+        Roo.get(document.body).on('mousemove', stopper, this);
+        var oldtitle = document.title;
+        var s = 1;
+        var _this = this;
+        var ivl = window.setInterval(function() {
+            
+            if (stop) {
+                Roo.get(document.body).un('mousemove', stopper, this);
+                _this.notifyActive = false;
+                document.title = oldtitle;
+                window.clearInterval(ivl);
+                return true;
+            }
+            s = !s;
+            document.title = s ? msg : oldtitle;
+                  
+        }, 1000); // every 120 secs = 2mins..
+         document.title =   msg;
+        
+        
+        
+    },
+    
+    modules : false,
+    /**
+     * example:
+     * 
+     * Pman.register({
+          modKey : '00-admin-xxxx',
+          module : Pman.Tab.projectMgr,
+          region : 'center',
+          parent : Pman.layout
+        })
+     * 
+     */
+    register : function(obj) {
+        if (!obj.parent) {
+            if (obj.parent === false) {
+                //console.log(obj);
+                return;
+            }
+            
+            console.log(obj);
+        }
+        if (!obj.parent.modules) {
+            obj.parent.modules = new Roo.util.MixedCollection(false, function(o) { return o.modKey });
+        }
+        obj.parent.modules.add(obj);
+        
+    },
+    
+    buildModules : function(parent, onComplete) 
+    {
+        
+        var _this = this;
+        var cmp = function(a,b) {   
+            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
+            
+        };
+        if (!parent.modules) {
+            return;
+        }
+        parent.modules.keySort('ASC',  cmp );
+        var mods = [];
+        
+        
+        // add modules to their parents..
+        var addMod = function(m) {
+           // console.log(m.modKey);
+            
+            mods.push(m);
+            if (m.module.modules) {
+                m.module.modules.keySort('ASC',  cmp );
+                m.module.modules.each(addMod);
+            }
+            if (m.finalize) {
+                m.finalize.name = m.name + " (clean up) ";
+                mods.push(m.finalize);
+            }
+            
+        }
+        parent.modules.each(addMod);
+        //this.allmods = mods;
+        //console.log(mods);
+        //return;
+        if (!mods.length) {
+            if (onComplete) onComplete();
+            return;
+        }
+        // flash it up as modal - so we store the mask!?
+        Ext.MessageBox.show({ title: 'loading' });
+        Ext.MessageBox.show({
+           title: "Please wait...",
+           msg: "Building Interface...",
+           width:450,
+           progress:true,
+           closable:false,
+           modal: false
+          
+        });
+        var n = 0;
+        var progressRun = function() {
+            
+            var m = mods[n];
+            
+            
+            Ext.MessageBox.updateProgress(
+                (n+1)/mods.length,  "Building Interface " + (n+1) + 
+                    " of " + mods.length + 
+                    (m.name ? (' - ' + m.name) : '')
+                    );
+            
+            
+            
+            if (typeof(m) == 'function') {
+                m();
+                
+            } else {
+                if (m.parent.layout && !m.module.disabled) {
+                    m.module.add(m.parent.layout, m.region);    
+                }
+                
+            }
+            
+            
+            n++;
+            if (n >= mods.length) {
+                onComplete();  
+                return;
+            }
+                
+            
+            progressRun.defer(10, Pman);    
+        }
+        progressRun.defer(1, Pman);
+     
+        
+        
+    },
+    
+    gtranslate : function(str, src, dest, cb) {
+        // load script: 
+        
+        
+        var x = new Roo.data.ScriptTagProxy({ 
+            url:  'http://ajax.googleapis.com/ajax/services/language/translate', 
+            callbackParam : 'callback' 
+        });
+        x.load(
+            {
+                v: '1.0',
+                q : str,
+                langpair : src + '|' +dest
+            }, // end params.
+            { // reader
+                readRecords : function (o) {
+                    if (!o.responseData) {
+                        return o;
+                    }
+                    return o.responseData.translatedText;
+                }
+            }, 
+            function (result) {
+                cb(result);
+            },
+            this,
+            []
+        );
+        
+            
+        
+    } ,
+    invertColor : function(c)
+    {
+        // read..
+        var ca = [];
+        for(var i = 0; i < 3; i++){
+            ca[i] = parseInt(c.charAt((i*2)+1) + c.charAt((i*2)+2), 16);
+        }
+            
+        // invert..
+        var col = '';
+        Roo.each(ca, function(hi) {
+            var h = parseInt(255-hi).toString(16);
+            if(h < 16){
+                h = '0' + h;
+            }
+            col += h;
+        });
+        return '#' + col;
+        
+    }
+    
+    
+    
+    
+    
+    
+    
+});
+    
diff --git a/SendIntro.php b/SendIntro.php
new file mode 100644 (file)
index 0000000..be055fb
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * assignment management - for supplier.s
+ * 
+ * call sigs:
+ *   
+ *   _createPasswd : 1  = generate a password
+ *   rawPasswd : use this as a password
+ *    
+ *   _create : 1    (create the account)
+ *      email : email address
+ *      if _createPassword is empty and rawPasswd is empty, then no message is sent.!!!!
+ *   
+ *   _create : 0 // or not set - password sending only.
+ *     id : id of person..
+ *     
+ * 
+ */
+
+require_once 'Pman.php';
+
+class Pman_Core_SendIntro extends Pman
+{
+    
+    function getAuth() 
+    {
+        
+        $au = $this->getAuthUser();
+        if (!$au) {
+            $this->jerr("Not authenticated", array('authFailure' => true));
+        }
+        $this->authUser = $au;
+        // check that it's a supplier!!!! 
+        
+        return true; 
+    }
+    
+    function post()
+    {
+        //DB_DataObject::debuglevel(1);
+        //  gets id : c.id,  rawPasswd: c.rawPasswd
+        
+        if (!$this->hasPerm("Core.Person", "A")) {
+             $this->jerr("Not Permitted - no permission to add users.");
+        }
+        $p = DB_DataObject::factory('Person');
+        
+        // let's make a password anyway..
+        $rawPasswd = false;
+        if (!empty($_REQUEST['_createPasswd'])) {
+            require_once  'Text/Password.php';
+            $rawPasswd = Text_Password::create(6). rand(11,99);
+        }
+        if (!empty($_REQUEST['rawPasswd'])) {
+            $rawPasswd = $_REQUEST['rawPasswd'];
+        }
+        
+        $id = empty($_REQUEST['id']) ? 0 : $_REQUEST['id'];
+        
+        if (!empty($_REQUEST['_create'])) {
+            // check account does not exist yet..
+            if ($p->get('email', $_REQUEST['email'])) {
+                $this->jerr("duplicate email address:" .$_REQUEST['email']);
+            }
+            $p = DB_DataObject::factory('Person');
+            $p->setFrom($_REQUEST);
+            
+            if ($rawPasswd == false) {
+                // -- needed for bulk adding... ?*** not sure why it's here, rather than in Roo?
+                $p->insert();
+                $this->jok("OK");
+                
+            }
+            // generate a password.
+            
+            
+            $p->insert();
+            $id = $p->id;
+            
+        } 
+        
+        
+        $p = DB_DataObject::factory('Person');
+        
+        if (!$id || !$p->get($_REQUEST['id']))  {
+            $this->jerr("Invalid user id");
+        }
+        
+        
+        if ($rawPasswd !== false) {
+            $p->setPassword($rawPasswd);
+            $p->update();
+        }
+        // next.. 
+        
+        
+        $p->sendTemplate('password_welcome', array(
+            'sender' => $this->authUser,
+            'rawPasswd' => $rawPasswd,
+            'baseURL' => $this->baseURL,
+        ));
+        
+        
+        $this->jok("SENT");
+        
+        // 
+       
+         
+    }
+    
+} 
\ No newline at end of file
diff --git a/SimpleExcel.php b/SimpleExcel.php
new file mode 100644 (file)
index 0000000..fddca0e
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * class to generate excel file from rows of data, and a configuration.
+ * 
+ * cfg:
+ *     formats 
+ *          name : [ Align : left, .... ]
+ *     workbook : nameof 
+ *     close :  array(
+            array(
+                'header'=> "Thumbnail",
+                'dataIndex'=> 'id',
+                'width'=>  75,
+                'renderer' => array($this, 'getThumb')
+            ),
+ */
+
+
+class Pman_Core_SimpleExcel extends Pman
+{
+    
+    
+    
+    function Pman_Core_SimpleExcel($data,$cfg)
+    {
+     //  print_r($cfg);
+        require_once 'Spreadsheet/Excel/Writer.php';
+        $pman = new Pman();
+        // Creating a workbook
+        $outfile2 = $pman->tempName('xls');
+       // var_dump($outfile2);
+        $workbook = new Spreadsheet_Excel_Writer($outfile2);
+        //$workbook = new Spreadsheet_Excel_Writer();
+        $workbook->setVersion(8);
+        // sending HTTP headers
+        
+        $formats = array();
+       
+        $cfg['formats'] = isset($cfg['formats']) ? $cfg['formats'] : array();
+        foreach($cfg['formats'] as $f=>$fcfg) {
+            $formats[$f] = & $workbook->addFormat();
+            foreach($fcfg as $k=>$v) {
+                $formats[$f]->{'set' . $k}($v);
+            }
+             
+        }
+         
+
+        
+        // Creating a worksheet
+        $worksheet =& $workbook->addWorksheet($cfg['workbook']);
+        $worksheet->setInputEncoding('UTF-8'); 
+         
+        foreach($cfg['cols'] as $c=>$col_cfg) {
+            $worksheet->write(0, $c, $col_cfg['header']);
+            $worksheet->setColumn ( $c, $c, $col_cfg['width'] / 5);
+             
+        }
+           //     DB_DataObject::debugLevel(1);
+        foreach($data as $r=>$cl) {
+            
+            if (isset($cfg['row_height'])) {
+                $worksheet->setRow($r+1, $cfg['row_height']);
+               }
+            
+            foreach($cfg['cols']  as $c=>$col_cfg) {
+                $v = isset($cl[$col_cfg['dataIndex']]) ? $cl[$col_cfg['dataIndex']] : '';
+                if (empty($cl[$col_cfg['dataIndex']])) {
+                    continue;
+                }
+                if (isset($col_cfg['txtrenderer'])) {
+                    $v = call_user_func($col_cfg['txtrenderer'], 
+                            $cl[$col_cfg['dataIndex']], $worksheet, $r+1, $c, $cl);
+                    if ($v === false) {
+                        continue;
+                    }
+                  //  var_dump($v);
+                }
+                if (isset($col_cfg['renderer'])) {
+                    continue;
+                }
+                
+                $v = @iconv('UTF-8', 'UTF-8//IGNORE', $v);
+                $format = isset($col_cfg['format']) ? $formats[$col_cfg['format']] : false;
+                
+          //    echo "<PRE>WRITE: ". htmlspecialchars(print_r(array($r+1, $c,$v), true));
+                $worksheet->write($r+1, $c, $v, $format);
+            }
+        }
+        
+        foreach($data as $r=>$cl) {
+        
+            foreach($cfg['cols']   as $c=>$col_cfg) {
+                $v = isset($cl[$col_cfg['dataIndex']]) ? $cl[$col_cfg['dataIndex']] : '';
+                if (empty($cl[$col_cfg['dataIndex']])) {
+                    continue;
+                }
+                if (isset($col_cfg['renderer'])) {
+                    call_user_func($col_cfg['renderer'], $cl[$col_cfg['dataIndex']], $worksheet, $r+1, $c, $cl);
+                    
+                }
+              //  echo "<PRE>WRITE: ". htmlspecialchars(print_r(array($r+1, $c, $cl[$col_cfg['dataIndex']]), true));
+         
+            }
+        }
+           $workbook->close();
+        $this->outfile2 = $outfile2;
+         
+    }
+    
+    function send($fn)
+    {
+        
+     
+       
+        require_once 'File/Convert.php';
+        $fc=  new File_Convert($this->outfile2, "application/vnd.ms-excel");
+        $fn = $fc->convert("application/vnd.ms-excel"); 
+        $fc->serve('attachment',$fn); // can fix IE Mess
+    }
+     
+    
+}
\ No newline at end of file
diff --git a/UploadProgress.php b/UploadProgress.php
new file mode 100644 (file)
index 0000000..191ca3a
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+require_once  'Pman.php';
+class Pman_Core_UploadProgress extends Pman
+{
+  function getAuth() {
+        
+        $au = $this->getAuthUser();
+        if (!$au) {
+             $this->jerr("Not authenticated", array('authFailure' => true));
+        }
+        $this->authUser = $au;
+        // check that it's a supplier!!!! 
+        
+        return true; 
+    }
+    function get()
+    {
+        
+        
+        header("Cache-Control: no-cache, must-revalidate");
+        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+        
+        if (  !function_exists('uploadprogress_get_info')) {
+            $this->jok(false);
+           }
+        
+        if (!empty($_GET['id'])) {
+           // var_dump(uploadprogress_get_info($_GET['id']));
+            $this->jok(uploadprogress_get_info($_GET['id']));
+        }
+        $this->jerr("no data");
+    }
+    
+}
\ No newline at end of file
diff --git a/compiled/Core.js b/compiled/Core.js
new file mode 100644 (file)
index 0000000..b81c120
--- /dev/null
@@ -0,0 +1,539 @@
+if (typeof(_T) == 'undefined') { _T={};}
+_T["88d66c37128476736b8c2a9cd9a87917"]="";
+_T["da27970c3ea08e35a23fb956908b78f4"]=" of ";
+_T["cf72aae865f3f0be736987f7dc390e25"]="Error";
+_T["5359af676f739607431a729778549fdd"]="Logout";
+_T["cd4b091c7fe3281497a3b47dfb18e9d9"]="Confirm";
+_T["02e3cddd44d16389541b6aeb8c790ecc"]="Deleting";
+_T["afaa6ac88a5c532720f81ab8d1cf345d"]=" (clean up) ";
+_T["ae2d276741dbe18ea7d82cf45e690b71"]="Add New Item";
+_T["7b085783b608ea949c9fb9de84016b78"]="Error Sending";
+_T["e84cbf769d01c3cf5f2470839353035a"]="Error Deleting";
+_T["584ad7a39665abc10933dac2838302f9"]="Error download";
+_T["1c34c8962b28be597267aef253b4694b"]="Please wait...";
+_T["852039f0b664305547a9ce2768a131a4"]="invalid in_out";
+_T["0902cdfae7b5ebaa525d4dd4fc121adb"]="Change Password";
+_T["51ff98c417d79325f91861af9c61cfb3"]="Building Interface ";
+_T["4177e7e2dbe28af7f72338aaeb603afd"]="Problem Loading Data";
+_T["6a4a6d2119244f74b8d02f20ef005c5e"]="Building Interface...";
+_T["b636c0e59d884e880fb4ca5fda048cf4"]="Error loading details";
+_T["b5f19c6de6e6bde8526a37c2a842e149"]="Loading Document details";
+_T["fdf760f049c0a779ad7e88cca6dc642d"]="Connection timed out sending";
+_T["9541c362ba7c5444620fc19601a3372d"]="Select at least one Row to delete";
+_T["3fdc18a65a1b517a5009529425c3565b"]="Please Correct all the errors in red";
+_T["d062a6fe1b74c46d5384e0e4595db834"]="Are you sure you want to delete that?";
+_T["c4eac334a309182656c84b3c69d6337b"]="You are Logged in as <b>{0} ({1})</b>";
+_T["7aabc9f3cf1f6785a4bc4dd0f1a2a321"]="Saving failed = fix errors and try again";
+_T["6ba73887c9a59d4caa85658209534ee8"]="Problem Connecting to Server - please try again.";
+_T["695b0048e081cdd0c1905fde237462bc"]="Closing this window will loose changes, are you sure you want to do that?";
+
+_T["f6551e5409cd0bd1293c73466c0d5a71"]="To";
+_T["adaa177b337c92793900a09979b7644f"]="Type";
+_T["e82288f1b4eba83e3912993b59e9874c"]="Project";
+_T["993475eb7faf2229459aa6ca1c3745e9"]="Sent To";
+_T["dacaeb74293d8e9bb58c28681b02c321"]="Searching...";
+_T["f7e6a2016c5b5f0113b18708d84db782"]="Enter Sent To";
+_T["2b617d7e2e8fdfe8fee08f5086f6e7b7"]="Select Office";
+_T["8e24b2c00ecb83fdbedee6634dbe7a6e"]="Select Project";
+_T["964610e35dbc2d5e2ef34f1492eff1c7"]="Office / Department";
+_T["f3ae3d381d60864b13244e2ac16c12fe"]="Select Document Type";
+_T["397925800f038e68f28adacc0c39d6ca"]="Select an address to add.";
+
+_T["c1d17a6224927a2a9fedfe19d7a211c3"]="Country";
+_T["1715e2ee8fbb45f3bb264d9806719b71"]="Currency";
+_T["9bc63702145bdb09708fa539aeefd725"]="Language";
+_T["4e58ecc198012e7ff1b9c77d4617498f"]="Country(s)";
+_T["9cdc0fbfc6a23315187fe5cea6cd9c59"]="Language(s)";
+_T["0202dbdb1d198fc99ff5e6a12dc1d1ff"]="Searching...";
+_T["a11dac8be1a6f587eedf4a1c1e2699ae"]="Select Country";
+_T["09e12895bf6d4b9974098883faa51a0b"]="Select Currency";
+_T["abbb23b334572407b19d843b3dfa3ee5"]="Select Language";
+_T["b9cd67022614720c2f168ce18ab32b1c"]="Select a country to add.";
+_T["3b073f6f35aed6785dbccdf6ea9ecd13"]="Select a language to add.";
+
+_T["e5c7255d15759b64bbee6c623c299744"]="20";
+_T["356c052df252f5f41bf445742c4a9e92"]="text";
+_T["8391d964e04c0c30d9f19bf036136c8d"]="Error";
+_T["68156a5e398303b805bd96fbc6b1f8ee"]="Login";
+_T["20f52c7354a3fd19843e600c53121d94"]="Sorry";
+_T["23e3b3bf16c1b9ee0b448a20cde1d8a0"]="input";
+_T["463c573d3aed3795e9e3145f10cd1416"]="Notice";
+_T["9eba57f4ad82997225a340c5c140a869"]="Warning";
+_T["b2a3486b5105e365dae1a1796390ba42"]="Language";
+_T["3b9a78188b115fa00e2285cd1047a02e"]="Password";
+_T["31cfba7708e9535c79660355d0f8accf"]="Logging in";
+_T["7e698d4c146d9eefd5dcd10552b18098"]="Email Address";
+_T["b2d0ea65f8ae06179a40d78e52b7833c"]="Forgot Password";
+_T["9055d707d0388278ceb4f35426316c1b"]="Fill in your email address";
+_T["1ba0950dff36aebd0c55f3b195edcb11"]="Language not available yet (";
+_T["2409934e0552cdd76753d2c11005b6b5"]="Problem Requesting Password Reset";
+_T["b9f8e134e8143020e2eb596292c7c1d1"]="Error logging out. - continuing anyway.";
+_T["c1b8242e54c06ad890a6a091195f7b8e"]="Login failed - communication error - try again.";
+_T["54242987801741c4105cfa0435d9912e"]="Error getting authentication status. - try reloading";
+_T["de7b06c26e8b5361eb8e33d068dd2ce4"]="Please check you email for the Password Reset message";
+_T["5d5717e963d28007da9511d1416cbc43"]="This is an open system - please set up a admin user with a password.";
+_T["4b0bb0bd607983ab0061a86db7fc7ba2"]="Error getting authentication status. - try reloading, or wait a while";
+
+_T["e4fe205ae80b87b90434e12e5e3a4c9b"]="Click to view PDF";
+
+_T["e7cf748ba346b55abdcc4b23eee865f2"]="Save";
+_T["f63d2ff3c0824d9a6d914b023170a0e7"]="Error";
+_T["584228d91d54c791da0c7b9f60eb0568"]="Cancel";
+_T["7e627bc5cadbc3aa73653b2e65eebf41"]="Sending";
+_T["3b504c4d3b791c1aa278926f21482646"]="Uploading";
+_T["6644290819b3cd82cd7a447b4f9082d9"]="Upload Image or File";
+_T["6bb7047abac30e5f215a55ee1258d63e"]="Error loading details";
+_T["180ab418d1431a5e3ab16412df46995c"]="Upload Image or  File";
+_T["de7fa9da20484d1ee51e3e11385b106a"]="Saving failed = fix errors and try again";
+
+_T["85a92c56516f8b4fb28cef275e39aa59"]="fax";
+_T["09216d718e93d47e7fab400386e0e666"]="Save";
+_T["55d8a63eb4ad34aaf8a64e677a7ba02e"]="Email";
+_T["e726c3820bd60bc1c312fb8c51dc3642"]="Phone";
+_T["1832ff6f8f4dc04e11d8da18197bd04e"]="Cancel";
+_T["1576472bc936da286e17816117c69800"]="Address";
+_T["b41c4b23e06e87f60c5cb0bd5bf4de81"]="Company";
+_T["4e53f9de03e95a51293bbd4c2518cc7d"]="Enter fax";
+_T["69424c2ba40b27522c5f582fbe4b754b"]="Enter name";
+_T["20c803184f4250311d36b34678a81e99"]="Enter email";
+_T["085c2f603ebade12c9f292ef40fd6b07"]="Enter phone";
+_T["c8805cab313fc29f3642f9a5c7f9aa64"]="Enter address";
+_T["526fafd56ab833df1f4ffd447600a9d1"]="Office / Department / Sub Comp. Name";
+_T["7836ab6fe8fe6f6ec502b3108a13e21d"]="Edit Office / Department / Sub Company";
+
+_T["3e8788f13c62d5400e2eef9ce61ff6d6"]="Edit Contact Details";
+
+_T["0f65f59038860dbf03201afab99fe7e1"]="Add";
+_T["0537a153a0e54447d83d2c8d094a03d1"]="Edit";
+_T["45e376f384cdb1f67a866700b892b3e8"]="Name";
+_T["081fcfe0460716e500eeab497d45d6b8"]="Error";
+_T["1eeb327bd294d207da46d9cfb93f9042"]="Delete";
+_T["726e57af6b8966adfdcaa385105de4d1"]="Reload";
+_T["0b0e4ee0b6875cbaa307a8d7f3c3d7ee"]="All Staff";
+_T["0534e1944a96427d47b562c494d85447"]="Everybody";
+_T["178044591ed0652d2b82b7f7eb90b22a"]="Select a Row";
+_T["b9b270f938cabca10640a932c830a4ce"]="Adminstrators";
+_T["982d7a1e24433e552a3d694a095f053e"]="Manage Groups";
+_T["d5cd30d9a8889de9ad91d34e09da494b"]="Not in a Group";
+_T["f845801a4be23199251c41e1c2ac5e98"]="Select only one Row";
+_T["2d481b48a578e9122e0cda91604a73b1"]="You can not delete that group";
+_T["075c26b58d3827f7726bb1eb7c2d13dc"]="You can not rename that group";
+_T["8b2b7b9a1be82d2550e1d2bf71504f40"]="All Staff (Default Permissions)";
+
+_T["39c8bb31d465dfc147324be427ace5e9"]="Add";
+_T["1ee4e8e2d1859ff63a7b58f29505249f"]="Fax";
+_T["f405b2cca36f62eb81fa563a0b7406ac"]="No ";
+_T["d1ff8ffcb0bc971614aef7c0b5a07290"]="Edit";
+_T["aacd489f97738135f87d1c85be64536b"]="Name";
+_T["42fcc3face9df26268d1c2bf30dcd747"]="Email";
+_T["bf5c8b4410513986dffc6d6d6f025c5f"]="Error";
+_T["0bfc17408bdeecfce4652e09c3b90621"]="Phone";
+_T["25310235b726d71d9d0bc2fc903b9a3b"]="Staff";
+_T["7bca1e8820519d2993ebabfa434007c9"]=" found";
+_T["54bf9f5699148960b91086f351cf159e"]="Active";
+_T["1984cf10277dee6c3ff92d27c3b05493"]="Delete";
+_T["f128b31c31b3754f5792d2eefdca21d0"]="Search";
+_T["4d49b66bbfd392f5307e93c277054732"]="Project";
+_T["0c87cd7a6911dfa20a87e9073a4891f0"]="Sending";
+_T["a89b59994ae0fe49d108d3e22d68a8f3"]="Bulk Add";
+_T["4788be05034a6a24e08add98ed12fddf"]="Displaying ";
+_T["bd87244321a326daa26695ab4b721c7c"]="Company Type";
+_T["87472631093f63c722db73519eb9e4b9"]="Reset Search";
+_T["f8eeb7a5fd0bed49c85e3664518a5e7c"]="Select a Row";
+_T["864c4e5c64245516e1fcdabaf49b8de1"]="Error Sending";
+_T["022426919cf2c4cb91db4d37dbe5d24c"]="Toogle Active";
+_T["2bcbf24c822c1428b849349709d432b4"]="Hide old staff";
+_T["3bb13cf053c9459ba5f2bad62a2e208b"]="Office / Dept.";
+_T["40c16e64d6bf564aa75d2287d06c9a7b"]="Show old staff";
+_T["118585dae50b38d2079b28afa5d768d6"]="Role / Position";
+_T["60c647263578176b102261a5ae1004a6"]="Company / Office";
+_T["0a1ea6b8f312884c024a49ea271b6330"]=" {0} - {1} of {2}";
+_T["ecb1973f7aa6a900a49efa65dfc18da4"]="Select People Row";
+_T["8d7a86f0b9a3f7f52e7b49206b42f1ff"]="Select only one Row";
+_T["d559132c96908612dd66163dbd532812"]="Drag person to add or remove from team";
+_T["469845eeeb8c7f2983a5fc6550af4dc7"]="Drag person to add or remove from group";
+
+_T["f7c61a97b669d7f5128b51c8644c400c"]="Save";
+_T["db88368227b739ed12b165005f43d2c9"]="Error";
+_T["9b6839c225da5cb93c3bf29720e0531d"]="Cancel";
+_T["1b6ed9a99ae0f49a874fab476d0e70c4"]="New Password ";
+_T["eadd75daa6471a87eb75121dd5eab06a"]="Change Password";
+_T["39b3f1da7208ad35ea991d47bb460b30"]="Error loading details";
+_T["a217bd43e7427e981bc8dbf18998faed"]="Passwords do not match";
+_T["78a7430d961bec5b3d4759206ebc2b04"]="Enter Passwords in both boxes";
+_T["23b47796783d663d3113bde8469f9202"]="Please Correct all the errors";
+_T["6f52a45578b8376c688a75ddc7888122"]="New Password (type again to confirm)";
+_T["25092a9a028d282401e526d9252c734d"]="Saving failed = fix errors and try again";
+
+_T["bd58983405ed76181a8d0ce7223d2780"]="";
+_T["c2257f446d410ea7a44b2f3fd68baa4a"]="By";
+_T["f1a3e388543d7a8d39f1a3d4ade58b94"]="Code";
+_T["00f5ccf184f1ff533931bde4424040b2"]="Date";
+_T["d825914fad6e57c9d1acac55bc74f464"]="Save";
+_T["0699fc5c5d74dce96c828c6e578ece63"]="Team";
+_T["0e8ccf88135bae007b5cff5837e3e197"]="Cancel";
+_T["ff40386a43ccfe9066f7ebe51992cd86"]="Client";
+_T["59242789e33d13385e7775bc7421464e"]="Remarks";
+_T["45e0394905808bcc80c34202748ddb13"]="Select Team";
+_T["59222ad07bc6410bf27eab7d035b409d"]="Edit Project";
+_T["2e6569fe7187cf7b776eebf79012c19c"]="Project Name";
+_T["7ca882603340513c5a17a92e2ba98140"]="Project type";
+_T["4a17dd69fb7066cf43bf7c5f3d9e4cc6"]="Searching...";
+_T["b72ffe66d7fb5278bc886ee23dbda9fa"]="File Location";
+_T["720eb6ec8a30c82c92847a11ee6d32e6"]="Select Client";
+_T["b90aa2ba8fe6d79a85c11ef4034f1f86"]="Enter Date Opened";
+_T["9384bc850b628f21d964769bd7d13e44"]="Enter Project Code";
+_T["be3b8a3bb525b99922adf15223852b6a"]="Enter Project Name";
+_T["0ebe06a05911b24af87a933ca81882a0"]="Enter Project Remarks";
+_T["5fcc9c08873869529a4c0f640c34b803"]="Select Person Who opened";
+_T["4206f45d33f6d7d12e9e7b6efc86e0de"]="Where are the files stored?";
+
+_T["5595a13ebb30e328ffb5b6def210a94c"]="fax";
+_T["59c001255d821a2e12e8fb705dba9fea"]="Save";
+_T["4e3ed651f76a84604309db4a263b8e44"]="Email";
+_T["e3aa17d446c7005272762934b3b1e1a0"]="OWNER";
+_T["f111792776dd00af4e9575dffce62c41"]="Phone";
+_T["e35c34d957d7aebd0c9e37aa77f50b70"]="Cancel";
+_T["59bfcea58d8c79f4a8cc2ce8256a167a"]="Client";
+_T["7688941a47dfb4d4edaaf460f81d69ab"]="Address";
+_T["5f679f3c301a24b3f538a9766ee3ae6e"]="Loading";
+_T["7931e6a8fdc03aeb23619c11057cfb46"]="Remarks";
+_T["650deecbb5e829066db9b03be1125a1c"]="Consultant";
+_T["692e49978c615ffee8b37ed3a8ef2a12"]="Contractor";
+_T["75d069b37c5159f5acb5d01d10a2d9a3"]="Enter code";
+_T["9c24ec3378fb01fb54d25c2075d3293d"]="Logo Image";
+_T["ce9ba64bb3f29723e000efb2e80abb8e"]="Add Company";
+_T["81cbd120755795f72b127151e540cde5"]="Select Type";
+_T["37b6f9357707805a4612ebc166766ee2"]="Company Name";
+_T["4cf24f0f74944b39fd350182d5e15817"]="Edit Company";
+_T["3fbd4316b2e824257633036893085545"]="System Owner";
+_T["f5978f4e5815e0516744069dd287e5d9"]="Upload Image";
+_T["bcde687f68818bdff785998f3f4b4dcc"]="Enter Address";
+_T["978731b3f7cb08990f958c25b4cc9702"]="Enter remarks";
+_T["daed45fe377199115ee46b87eb340dcc"]="Edit Companies";
+_T["73fe964a2d78700ea90ec792a87cb425"]="Enter fax Number";
+_T["4c63cd35411e0bfe84d30f523cf6b93a"]="Background Colour";
+_T["31e77d71bd68053a7d6fcd4bc974af6a"]="No Image Attached";
+_T["490679f6791d65bc9998cadb629c7053"]="Add / Change Image";
+_T["8ffc3bf05859510e6dc4613b607cdcbe"]="Change / Add Image";
+_T["d0845cdf23eb01488ec78802847e0273"]="Enter Company Name";
+_T["7512ebcca5961d7894b501b6b0556c36"]="Enter Phone Number";
+_T["0e671bf5ff1cf6b299f895f78678121b"]="No Image Available";
+_T["5caf4f1f1ea765a217064568800b9eee"]="Enter Email Address";
+_T["1f0d43f377b93713beb48cbaca0e4401"]="Your Company Details";
+_T["857adf078513b5f11f815595aa0f9fd1"]="Company ID (for filing Ref.)";
+
+_T["aacd89f134545118f60a671de60913d3"]="New Contact Details";
+
+_T["bc619e5bc0e08070f5aea669b1afdba1"]="Edit Contact Details";
+
+_T["386f61f04d35fedb1ab564f275a0cc37"]="Add / Edit Staff";
+
+_T["4545094571d2bd9ce3dfc20783cf3dbc"]="No";
+_T["2b80fb0dc406c89322d30ed0c0f6150b"]="\n";
+_T["b3d5fbd734ec40cdb88c7e544b737e57"]=" : ";
+_T["6eab94585302a1eb047d8ad46a822fe1"]="Fax";
+_T["035ee8612761bb1546093a1b22451b67"]="Yes";
+_T["78800f89af27b724063900f2ac603ea8"]="Done";
+_T["7033b8924378a2098ecf784128d96125"]="Save";
+_T["fef6c4502e830f3cb17ceda089079d08"]="Email";
+_T["7825faf6d798725b4f9c36122dc0d78f"]="Error";
+_T["8ecda72b47a4d87945396f1deb3a4e2b"]="Phone";
+_T["687a326482448749613f378d040f6ef6"]="Cancel";
+_T["be407624d99fa1d3edd7ff59c079dd62"]="Office";
+_T["92e1985e19c2bb5d9556ac7ba52d5a7a"]="Company";
+_T["4f53be722b07293542247cc405232a69"]="Done - ";
+_T["ecb6cc539899477d30b822eab4f51b57"]="Loading";
+_T["b5506f1d5c8fcd78b22b830ce30a377f"]="Project";
+_T["b57f7c3a947d7a7a24dcce08a1f789ec"]="Sending";
+_T["bbc9b7422ae486331486a0734c399109"]="Enter fax";
+_T["801f9098abec829acfaad24d9c38acf1"]="Enter name";
+_T["fac109c69eeb67ebda3c5e40393bcb9b"]="Action Type";
+_T["b9b189c9b68fd2072e2937f60042e970"]="Enter email";
+_T["43a33d905d2c47dcd5afccb8d6c5c9ec"]="Contact Name";
+_T["4b59409465457ad433c029640bf1a2c5"]="Searching...";
+_T["f81f0fdf4c6384f98a5d1f49ffd0ebe3"]="Send Welcome";
+_T["024116eeefc851698f4381072c88c988"]="New Password ";
+_T["99667c31cbee3c1649a9abfba6f76f5f"]="Select Office";
+_T["d4efe6bd99e2f9dca237692425cd1e37"]="Please wait...";
+_T["276038b1ea02816633ab56c087ab5e8b"]="Select Company";
+_T["82c0f8b8dd0cb58b397ee9d6f633749e"]="Action Required";
+_T["976cb754f8a3120a0d8ddecc7dad70b3"]="Role / Position";
+_T["4e8097f84abcc6d92ca69656d0e94024"]="Select a Company";
+_T["60c2576c3bd6fce9593dfafa60d5dc71"]="Enter phone Number";
+_T["453b606630064afeccae473d15cb21f1"]="No addresses found";
+_T["b41f06c5d4aa97be01660b5033f3c0b9"]="Office / Department";
+_T["56270c6137713c24a973c4239ef10a8c"]="Enter email addresse";
+_T["36e08fc5b447ea57d5f9801a0a594de8"]="Enter Role / Position";
+_T["f202ec7143eb64a7694663d5d795972b"]="Passwords do not match";
+_T["c5f95205dd78ae006d052009aa6142f8"]="Send Introduction Mail";
+_T["e81e0305bf7b9c0bff38b1bd4113a94b"]="Select An Company First";
+_T["6c755092c6556392d8f8589ea57ed32e"]="Select the Company Name";
+_T["98ca94191386d0d2cd58bd272d1df5d7"]="Sending Welcome Message";
+_T["598d3e15de6c0edc42bbb12bba56848c"]="Email address (one per line)";
+_T["9ea81314e83737179ff499c00215e349"]="Password (type again to confirm)";
+_T["ffe42f94e27e5228d3d2320e16dfb61b"]="Creating Account / Sending Welcome";
+_T["0734055957ed2deb78318855e001f072"]="Send Welcome Messages and Generate Passwords?";
+_T["28d4e53cb89a8406eaacfece36ecfbea"]="Always File Messages from this Person in Project";
+_T["c9f36f7b1c27b424e71ce6c66a2f000e"]="You must create a password for the admin account";
+_T["3a2644a946cf95a21e5890507232305f"]="You must create a password to send introduction mail";
+
+_T["3856b4848e0006d06445a3ec0026e6b9"]="Code";
+_T["7b0411b72ad383c3e2260d2293b0e2f7"]="Save";
+_T["918b8aa8008529245b10c94d04e201c6"]="Cancel";
+_T["ff98eddf5a2bfb7ab13af0efe685783b"]="Remarks";
+_T["ba960e685bbb3f9c913365a52e998454"]="Enter code";
+_T["04c4d9039b04ae1bb4143edcd3310cc3"]="Document Type";
+_T["cfa368a58af37baf0ff74f80a9d7f192"]="Enter remarks";
+_T["9566c872f5eb3606aff77e92ef404f6f"]="Edit Document Type";
+_T["16fdbf7788088cd5e4251adddf31957e"]="Enter Document Type";
+
+if(typeof (_T)=="undefined"){_T={};}Pman=new Roo.Document({subMenuItems:[],topMenuItems:[],rightNames:{},buildCompleted:false,events:{"beforeload":true,load:true,authrefreshed:true},listeners:{"ready":function(){if(typeof (console)=="undefined"){console={log:function(){}};
+}if(Ext.get("loading")){Ext.get("loading").remove();}Ext.state.Manager.setProvider(new Ext.state.CookieProvider());if(AppLinkError.length){Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],AppLinkError,function(){Pman.Login.onLoad();});return;}if(showNewPass.length){Pman.PasswordChange.show({passwordReset:showNewPass},function(A){Pman.Login.onLoad();
+});return;}Pman.Login.onLoad();},load:function(){if(Roo.get("loading-logo-tile")){Roo.get("loading-logo-tile").remove();}if(Roo.get("loading-logo-tile-top")){Roo.get("loading-logo-tile-top").remove();}if(Roo.get("loading-logo-bottom")){Roo.get("loading-logo-bottom").remove();
+}if(Roo.get("loading-logo-center")){Roo.get("loading-logo-center").remove();}}},layout:false,onload:function(){if(this.layout){return;}if(Ext.get("loading")){Ext.get("loading").remove();}if(Ext.get("loading-mask")){Ext.get("loading-mask").show();}var A=this;
+this.stime=new Date();this.layout=new Ext.BorderLayout(document.body,{north:{split:false,initialSize:25,titlebar:false},center:{titlebar:false,autoScroll:false,closeOnTab:true,tabPosition:"top",alwaysShowTabs:true,minTabWidth:140}});this.fireEvent("beforeload",this);
+this.layout.beginUpdate();this.layout.add("north",new Ext.ContentPanel("title","North"));var au=Pman.Login.authUser;if(au.id>0&&au.company_id_background_color.length){Ext.get("title").dom.style.backgroundColor="#"+au.company_id_background_color;Ext.get("headerInformation").dom.style.color=this.invertColor("#"+au.company_id_background_color);
+}if(au.id>0&&au.company_id_logo_id*1>0){Ext.get("headerInformation-company-logo").dom.src=baseURL+"/Images/"+au.company_id_logo_id+"/"+au.company_id_logo_id_filename;}else{Ext.get("headerInformation-company-logo").dom.src=Roo.BLANK_IMAGE_URL;}Ext.get("headerInformation").dom.innerHTML=String.format(_T["c4eac334a309182656c84b3c69d6337b"],au.name,au.email,au.company_id_name,AppVersion,appNameShort);
+document.title=appName+" v"+AppVersion+" - "+au.company_id_name;Ext.QuickTips.init();if(Ext.isGecko){Ext.useShims=true;}this.layout.beginUpdate();Pman.building=true;this.buildModules(this,function(){A.layout.getRegion("center").showPanel(0);A.layout.endUpdate();
+A.addTopToolbar();A.finalize();A.fireEvent("load",this);});},addTopToolbar:function(){var se=Pman.layout.getRegion("center").tabs.stripEl;var A=se.createChild({tag:"td",style:"width:100%;"});var C=new Ext.Toolbar(A);if(Roo.isSafari){var B=se.child("table",true);
+B.setAttribute("width","100%");}C.add(new Ext.Toolbar.Fill(),{text:_T["0902cdfae7b5ebaa525d4dd4fc121adb"],cls:"x-btn-text-icon",icon:rootURL+"/Pman/templates/images/change-password.gif",handler:function(){Pman.PasswordChange.show({});}},"-");if(this.topMenuItems.length){Roo.each(this.topMenuItems,function(mi){C.add(mi);
+});C.add("-");}if(this.subMenuItems.length){this.subMenuItems.sort(function(a,b){return a.seqid>b.seqid?1:-1;});this.subMenuItems.pop();C.add({text:_T["ae2d276741dbe18ea7d82cf45e690b71"],cls:"x-btn-text-icon",icon:Ext.rootURL+"images/default/dd/drop-add.gif",menu:{items:this.subMenuItems}},"-");
+}C.add({text:_T["5359af676f739607431a729778549fdd"],cls:"x-btn-text-icon",icon:rootURL+"/Pman/templates/images/logout.gif",handler:function(){Pman.Login.logout();}});},finalize:function(){window.onbeforeunload=function(e){var e=e||window.event;var r=_T["695b0048e081cdd0c1905fde237462bc"];
+if(e){e.returnValue=r;}return r;};Ext.MessageBox.hide();if(Ext.get("loading-mask")){Ext.get("loading-mask").remove();}this.buildCompleted=true;if(AppTrackOnLoad*1>0){this.onLoadTrack(AppTrackOnLoad,false);}var A=function(B){if(!B||!B.id){Pman.Dialog.PersonStaff.show({id:0,company_id:Pman.Login.authUser.company_id*1,company_id_name:Pman.Login.authUser.company_id_name},function(C){A(C);
+});return;}Ext.state.Manager.set("Pman.Login.username",B.email),window.onbeforeunload=false;document.location=baseURL+"?ts="+Math.random();};var forceCompany=function(B){if(Pman.Login.authUser.company_id*1>0){A();return;}if(!B||!B.id){Pman.Dialog.Companies.show({id:0,isOwner:1,comptype:"OWNER"},function(C){forceCompany(C);
+});return;}Pman.Login.authUser.company_id=B.id;Pman.Login.authUser.company_id_name=B.name;A();};if(Pman.Login.authUser.id<0){forceCompany();}},onLoadTrack:function(id,cb){this.onLoadTrackCall(id,cb,"DocumentsCirc_");},onLoadTrackEdit:function(id,cb){this.onLoadTrackCall(id,cb,"Documents_");
+},onLoadTrackCall:function(id,cb,B){Ext.get(document.body).mask(_T["b5f19c6de6e6bde8526a37c2a842e149"]);Pman.request({url:baseURL+"/Roo/Documents.html",params:{_id:id},method:"GET",success:function(C){Ext.get(document.body).unmask();switch(C.in_out){case "IN":B+="In";
+break;case "OUT":B+="Out";break;case "WIP":B+="Wip";break;default:Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],_T["852039f0b664305547a9ce2768a131a4"]);return;}Pman.Dialog[B].show(C,cb?cb:Pman.refreshActivePanel);},failure:function(){Ext.get(document.body).unmask();
+}});},hasPerm:function(C,B){if(typeof (Pman.Login.authUser)!="object"){return false;}if(typeof (Pman.Login.authUser.perms[C])!="string"){return false;}return Pman.Login.authUser.perms[C].indexOf(B)>-1;},Readers:{},ColModels:{},Forms:{},Tab:{},Dialog:{},processResponse:function(C){var B="";
+try{B=Ext.decode(C.responseText);if(typeof (B)!="object"){B={success:false,errorMsg:B,errors:true};}if(typeof (B.success)=="undefined"){B.success=false;}}catch(e){B={success:false,errorMsg:C.responseText,errors:true};}return B;},genericDelete:function(B,C){var r=[];
+var s=B.grid.getSelectionModel().getSelections();if(!s.length){Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],_T["9541c362ba7c5444620fc19601a3372d"]);return "";}for(var i=0;i<s.length;i++){r.push(s[i].data.id);}Ext.MessageBox.confirm(_T["cd4b091c7fe3281497a3b47dfb18e9d9"],_T["d062a6fe1b74c46d5384e0e4595db834"],function(D){if(D!="yes"){return;
+}B.grid.getView().mainWrap.mask(_T["02e3cddd44d16389541b6aeb8c790ecc"]);Pman.request({url:baseURL+"/Roo/"+C+".php",method:"GET",params:{_delete:r.join(",")},success:function(E){B.grid.getView().mainWrap.unmask();if(B.paging){B.paging.onClick("refresh");}else if(B.refresh){B.refresh();
+}else if(B.grid.footer&&B.grid.footer.onClick){B.grid.footer.onClick("refresh");}else{B.grid.getDataSource().load();}},failure:function(E){B.grid.getView().mainWrap.unmask();Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],_T["e84cbf769d01c3cf5f2470839353035a"]);
+}});});},refreshActivePanel:function(){var C=this.layout.getRegion("center").getActivePanel();if(C.controller&&C.controller.paging){C.controller.paging.onClick("refresh");return;}var B=Pman.layout.getRegion("center").getActivePanel().id;if(!B){return;}Pman.Tab[B].paging.onClick("refresh");
+},toCidV:function(B){return "C"+B.in_out.substring(0,1)+B.cid;},standardActionFailed:function(f,B,cb){if(B.failureType=="client"){Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],_T["3fdc18a65a1b517a5009529425c3565b"],cb);return;}if(B.failureType=="connect"){Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],_T["6ba73887c9a59d4caa85658209534ee8"],cb);
+return;}if(B.type=="submit"){Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],typeof (B.result.errorMsg)=="string"?String.format("{0}",B.result.errorMsg):_T["7aabc9f3cf1f6785a4bc4dd0f1a2a321"],cb);return;}Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],_T["b636c0e59d884e880fb4ca5fda048cf4"],cb);
+},request:function(c){Ext.Ajax.request({timeout:c.timeout||30000,url:c.url,method:c.method,params:c.params,xmlData:c.xmlData,success:function(D,C){var B=Pman.processResponse(D);if(!B.success){if(c.failure){if(true===c.failure.call(this,D,C)){return;}}Roo.MessageBox.hide();
+Ext.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],B.errorMsg?B.errorMsg:_T["7b085783b608ea949c9fb9de84016b78"]);return;}c.success.call(this,B.data);return;},failure:function(C,B){if(c.failure){if(true===c.failure.call(this,C,B)){return;}}Roo.MessageBox.hide();
+Roo.MessageBox.alert(_T["cf72aae865f3f0be736987f7dc390e25"],_T["fdf760f049c0a779ad7e88cca6dc642d"]);console.log(C);},scope:this});},csvFrame:false,createCsvFrame:function(){if(this.csvFrame){document.body.removeChild(this.csvFrame);}var id=Ext.id();this.csvFrame=document.createElement("iframe");
+this.csvFrame.id=id;this.csvFrame.name=id;this.csvFrame.className="x-hidden";if(Ext.isIE){this.csvFrame.src=Ext.SSL_SECURE_URL;}document.body.appendChild(this.csvFrame);if(Ext.isIE){document.frames[id].name=id;}},download:function(c){if(c.newWindow){window.open(c.url+"?"+Roo.urlEncode(c.params||{}),"_blank");
+return;}this.createCsvFrame();function cb(){var r={responseText:_T["88d66c37128476736b8c2a9cd9a87917"],responseXML:null};var C=this.csvFrame;try{var B=Ext.isIE?C.contentWindow.document:(C.contentDocument||window.frames[this.csvFrame.id].document);if(B&&B.body&&B.body.innerHTML.length){Ext.MessageBox.alert(_T["584ad7a39665abc10933dac2838302f9"],B.body.innerHTML);
+}}catch(e){}Ext.EventManager.removeListener(C,"load",cb,this);}Ext.EventManager.on(this.csvFrame,"load",cb,this);this.csvFrame.src=c.url;},downloadRevision:function(B,C){this.download({url:baseURL+"/Documents/Doc/DownloadRev/"+B.id+"/"+C+"/"+B.project_id_code+"-"+B.cidV+"-"+C+"-"+B.filename});
+},exportCSV:function(c){for(var i=0;i<c.csvFormat.length;i++){c.params["csvCols["+i+"]"]=c.csvFormat[i][0];c.params["csvTitles["+i+"]"]=c.csvFormat[i][1];}c.url+="?"+Ext.urlEncode(c.params);this.download(c);},prettyDate:function(B){if(typeof (B)=="string"){var ds=Date.parseDate(B,"Y-m-d H:i:s");
+if(ds){return this.prettyDate(ds);}ds=Date.parseDate(B,"Y-m-d");if(ds){return this.prettyDate(ds);}return "";}if(!B){return "";}var td=new Date();var C=Math.floor(td.getElapsed(B)/(1000*60*60*24));if(C<7){return B.dateFormat("D H:i");}if(td.dateFormat("m")==B.dateFormat("m")){return B.dateFormat("dS D");
+}if(td.dateFormat("Y")==B.dateFormat("Y")){return B.dateFormat("dS M");}return B.dateFormat("d M Y");},loadException:function(a,b,c,d){if(d&&d.authFailure){Pman.Login.show();return;}Roo.MessageBox.alert(_T["4177e7e2dbe28af7f72338aaeb603afd"],a.message||c.statusText);
+},notifyActive:false,notifyTitle:function(C){if(this.notifyActive){return;}var D=false;var F=function(){D=true;document.title=G;};Roo.get(document.body).on("mousemove",F,this);var G=document.title;var s=1;var E=this;var B=window.setInterval(function(){if(D){Roo.get(document.body).un("mousemove",F,this);
+E.notifyActive=false;document.title=G;window.clearInterval(B);return true;}s=!s;document.title=s?C:G;},1000);document.title=C;},modules:false,register:function(B){if(!B.parent){if(B.parent===false){return;}console.log(B);}if(!B.parent.modules){B.parent.modules=new Roo.util.MixedCollection(false,function(o){return o.modKey});
+}B.parent.modules.add(B);},buildModules:function(F,G){var D=this;var B=function(a,b){return String(a).toUpperCase()>String(b).toUpperCase()?1:-1;};if(!F.modules){return;}F.modules.keySort("ASC",B);var C=[];var E=function(m){C.push(m);if(m.module.modules){m.module.modules.keySort("ASC",B);
+m.module.modules.each(E);}if(m.finalize){m.finalize.name=m.name+_T["afaa6ac88a5c532720f81ab8d1cf345d"];C.push(m.finalize);}};F.modules.each(E);if(!C.length){if(G)G();return;}Ext.MessageBox.show({title:"loading"});Ext.MessageBox.show({title:_T["1c34c8962b28be597267aef253b4694b"],msg:_T["6a4a6d2119244f74b8d02f20ef005c5e"],width:450,progress:true,closable:false,modal:false});
+var n=0;var H=function(){var m=C[n];Ext.MessageBox.updateProgress((n+1)/C.length,_T["51ff98c417d79325f91861af9c61cfb3"]+(n+1)+_T["da27970c3ea08e35a23fb956908b78f4"]+C.length+(m.name?(" - "+m.name):""));if(typeof (m)=="function"){m();}else{if(m.parent.layout&&!m.module.disabled){m.module.add(m.parent.layout,m.region);
+}}n++;if(n>=C.length){G();return;}H.defer(10,Pman);};H.defer(1,Pman);},gtranslate:function(C,B,D,cb){var x=new Roo.data.ScriptTagProxy({url:"http://ajax.googleapis.com/ajax/services/language/translate",callbackParam:"callback"});x.load({v:"1.0",q:C,langpair:B+"|"+D},{readRecords:function(o){if(!o.responseData){return o;
+}return o.responseData.translatedText;}},function(E){cb(E);},this,[]);},invertColor:function(c){var ca=[];for(var i=0;i<3;i++){ca[i]=parseInt(c.charAt((i*2)+1)+c.charAt((i*2)+2),16);}var B="";Roo.each(ca,function(hi){var h=parseInt(255-hi).toString(16);if(h<16){h="0"+h;
+}B+=h;});return "#"+B;}});
+Pman.Std={project_id:function(A){A=A||{};A.storeListeners=A.storeListeners||{};return Roo.apply({width:200,fieldLabel:_T["e82288f1b4eba83e3912993b59e9874c"],name:"project_id_code",hiddenName:"project_id",allowBlank:false,selectOnFocus:true,qtip:_T["8e24b2c00ecb83fdbedee6634dbe7a6e"],xtype:"ComboBox",store:{xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/Roo/Projects.html",method:"GET"},reader:Pman.Readers.Projects,listeners:Roo.apply({loadexception:Pman.loadException},A.storeListeners),remoteSort:true,sortInfo:{field:"code",direction:"ASC"}},displayField:"code",valueField:"id",typeAhead:true,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{code}</b> {name}","</div>"),queryParam:"query[project_search]",loadingText:_T["dacaeb74293d8e9bb58c28681b02c321"],listWidth:400,minChars:2,pageSize:20},A);
+},company_id:function(A){A=A||{};A.storeListeners=A.storeListeners||{};A.listeners=A.listeners||{};return Roo.apply({name:"addressto_name",displayField:"name",fieldLabel:_T["993475eb7faf2229459aa6ca1c3745e9"],allowBlank:true,qtip:_T["f7e6a2016c5b5f0113b18708d84db782"],width:290,value:"",xtype:"ComboBoxAdder",selectOnFocus:true,allowBlank:false,store:{xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/Roo/Companies.html",method:"GET"},reader:Pman.Readers.Companies,listeners:Roo.apply({loadexception:Pman.loadException},A.storeListeners),remoteSort:true,sortInfo:{field:"name",direction:"ASC"}},typeAhead:true,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{name}</b> {address}","</div>"),queryParam:"query[name]",loadingText:_T["dacaeb74293d8e9bb58c28681b02c321"],listWidth:400,minChars:2,pageSize:20},A);
+},doctype_name:function(A){A=A||{};return Roo.apply({name:"doctype_name",width:290,fieldLabel:_T["adaa177b337c92793900a09979b7644f"],allowBlank:false,qtip:_T["f3ae3d381d60864b13244e2ac16c12fe"],value:"",xtype:"ComboBox",store:{xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/Roo/Document_Types.html",method:"GET"},reader:Pman.Readers.Document_Types,listeners:{beforeload:function(t,o){o.params.limit=9999;
+},loadexception:Pman.loadException},remoteSort:true,sortInfo:{field:"name",direction:"ASC"}},displayField:"name",typeAhead:false,editable:false,triggerAction:"all",selectOnFocus:true},A);},address_list_adder:function(A){A=A||{};A.storeListeners=A.storeListeners||{};
+return Roo.apply({name:"send_to",fieldLabel:_T["f6551e5409cd0bd1293c73466c0d5a71"],idField:"email",renderer:function(d){return String.format("{0}",d.name.length?d.name:d.email);},xtype:"ComboBoxLister",displayField:"name",value:"",qtip:_T["397925800f038e68f28adacc0c39d6ca"],selectOnFocus:true,allowBlank:true,width:150,store:{xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/Roo/Person.html",method:"GET"},reader:Pman.Readers.Companies,listeners:A.storeListeners,remoteSort:true,sortInfo:{field:"name",direction:"ASC"}},typeAhead:true,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{name}</b> {email}","</div>"),queryParam:"query[name]",loadingText:_T["dacaeb74293d8e9bb58c28681b02c321"],listWidth:400,minChars:2,pageSize:20,setList:function(ar){var B=this;
+Roo.each(ar,function(a){B.addItem(a);});},toList:function(){var B=[];this.items.each(function(a){B.push(a.data);});return B;}},A);},our_office_id:function(A){A=A||{};A.listeners=A.listeners||{};return Roo.apply({xtype:"ComboBoxAdder",fieldLabel:_T["964610e35dbc2d5e2ef34f1492eff1c7"],hiddenName:"office_id",name:"office_id_name",qtip:_T["2b617d7e2e8fdfe8fee08f5086f6e7b7"],width:300,allowBlank:true,triggerAction:"all",typeAhead:true,forceSelection:true,selectOnFocus:true,displayField:"name",valueField:"id",store:{xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/Roo/Office.html",method:"GET"},reader:Pman.Readers.Office,listeners:Roo.apply({loadexception:Pman.loadException},A.storeListeners),remoteSort:true,sortInfo:{field:"name",direction:"ASC"}},listeners:Roo.apply({adderclick:function(){var B={company_id:Pman.Login.authUser.company_id*1,company_id_name:Pman.Login.authUser.company_id_name,address:"",phone:"",fax:"",email:""};
+Pman.Preview.tmpDisable();Pman.Dialog.Office.show(B,function(C){_this.setFromData(C);Pman.Preview.tmpEnable();});}},A.listeners),tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{name}</b> {address}","</div>"),queryParam:"query[name]",loadingText:_T["dacaeb74293d8e9bb58c28681b02c321"],listWidth:400,minChars:2,pageSize:20},A);
+},country:function(A){return Pman.I18n.country(A);},language:function(A){return Pman.I18n.language(A);},languageList:function(A){return Pman.I18n.languageList(A);},countryList:function(A){return Pman.I18n.countryList(A);}};
+Pman.I18n={listToNames:function(B,D){var A=[];var C=this;var cl=D.split(",");Roo.each(cl,function(c){A.push(C.toName(B,c));});return A.join(", ");},toName:function(C,B){var A=B;Roo.each(Pman.Login.authUser.i18n[C],function(d){if(d.code==B){A=d.title;return false;
+}});return A;},listToObjects:function(B,D){var A=[];var C=this;if(!D.length){return A;};var cl=D.split(",");Roo.each(cl,function(c){A.push({code:c,title:C.toName(B,c)})});return A;},reader:{root:"data",totalProperty:"total",id:"code",xtype:"JsonReader",fields:["code","title"]},countryStore:function(){return {xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/I18N/Country.html",method:"GET"},reader:Pman.I18n.reader,listeners:{loadexception:Pman.loadException},remoteSort:false,sortInfo:{field:"title",direction:"ASC"}}},languageStore:function(){return {xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/I18N/Lang.html",method:"GET"},reader:Pman.I18n.reader,listeners:{loadexception:Pman.loadException},remoteSort:false,sortInfo:{field:"title",direction:"ASC"}}},currencyStore:function(){return {xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/I18N/Currency.html",method:"GET"},reader:Pman.I18n.reader,listeners:{loadexception:Pman.loadException},remoteSort:false,sortInfo:{field:"title",direction:"ASC"}}},country:function(A){var B=this;
+A=A||{};return Roo.apply({name:"country_title",hiddenName:"country",width:290,listWidth:300,fieldLabel:_T["c1d17a6224927a2a9fedfe19d7a211c3"],allowBlank:false,qtip:_T["a11dac8be1a6f587eedf4a1c1e2699ae"],value:"",xtype:"ComboBox",store:this.countryStore(),displayField:"title",valueField:"code",typeAhead:false,editable:false,triggerAction:"all",selectOnFocus:true},A);
+},language:function(A){var B=this;A=A||{};return Roo.apply({name:"language_title",hiddenName:"language",width:290,listWidth:300,fieldLabel:_T["9bc63702145bdb09708fa539aeefd725"],allowBlank:false,qtip:_T["abbb23b334572407b19d843b3dfa3ee5"],value:"",xtype:"ComboBox",store:this.languageStore(),displayField:"title",valueField:"code",typeAhead:false,editable:false,triggerAction:"all",selectOnFocus:true},A);
+},currency:function(A){var B=this;A=A||{};return Roo.apply({name:"currency_title",hiddenName:"currency",width:290,listWidth:300,fieldLabel:_T["1715e2ee8fbb45f3bb264d9806719b71"],allowBlank:false,qtip:_T["09e12895bf6d4b9974098883faa51a0b"],value:"",xtype:"ComboBox",store:this.currencyStore(),displayField:"code",valueField:"code",typeAhead:false,editable:false,triggerAction:"all",selectOnFocus:true,tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","{title} ({code})</b>","</div>")},A);
+},languageList:function(A){A=A||{};return Roo.apply({name:"language",fieldLabel:_T["9cdc0fbfc6a23315187fe5cea6cd9c59"],idField:"code",nameField:"title",renderer:function(d){return String.format("{0}",d.title);},xtype:"ComboBoxLister",displayField:"title",value:"",qtip:_T["3b073f6f35aed6785dbccdf6ea9ecd13"],selectOnFocus:true,allowBlank:true,width:150,boxWidth:300,store:this.languageStore(),editable:false,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","{title}</b>","</div>"),queryParam:"query[name]",loadingText:_T["0202dbdb1d198fc99ff5e6a12dc1d1ff"],listWidth:400,minChars:2,setList:function(ar){var B=this;
+Roo.each(ar,function(a){B.addItem(a);});},toList:function(){var B=[];this.items.each(function(a){B.push(a.data);});return B;}},A);},countryList:function(A){A=A||{};return Roo.apply({name:"countries",fieldLabel:_T["4e58ecc198012e7ff1b9c77d4617498f"],idField:"code",nameField:"title",renderer:function(d){return String.format("{0}",d.title);
+},xtype:"ComboBoxLister",displayField:"title",value:"",qtip:_T["b9cd67022614720c2f168ce18ab32b1c"],selectOnFocus:true,allowBlank:true,width:150,boxWidth:300,store:this.countryStore(),editable:false,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","{title}</b>","</div>"),queryParam:"query[name]",loadingText:_T["0202dbdb1d198fc99ff5e6a12dc1d1ff"],listWidth:400,minChars:2,setList:function(ar){var B=this;
+Roo.each(ar,function(a){B.addItem(a);});},toList:function(){var B=[];this.items.each(function(a){B.push(a.data);});return B;}},A);}};
+Pman.Login=new Roo.util.Observable({events:{"render":true},disabled:false,dialog:false,form:false,haslogo:false,authUserId:0,authUser:{id:false},checkFails:0,versionWarn:false,sending:false,onLoad:function(){if(Roo.get("loading")){Roo.get("loading").remove();
+}this.switchLang("en");Roo.Ajax.request({url:baseURL+"/Login.js",params:{getAuthUser:true},method:"GET",success:function(C,B){var A=Pman.processResponse(C);this.checkFails=0;if(!A.success){this.checkFails=5;return Pman.Login.failure(C,B);}if(!A.data.id){return this.show(true);
+}this.fillAuth(A.data);this.checkFails=0;Pman.onload();},failure:Pman.Login.show,scope:Pman.Login});},check:function(B){if(B){Pman.Login.checkFails++;}else{Pman.Login.checkFails=0;}var A=this;if(this.sending){if(Pman.Login.checkFails>4){Pman.Preview.disable();
+Roo.MessageBox.alert(_T["8391d964e04c0c30d9f19bf036136c8d"],_T["4b0bb0bd607983ab0061a86db7fc7ba2"],function(){A.sending=false;});return;}A.check.defer(10000,A,[true]);return;}this.sending=true;Roo.Ajax.request({url:baseURL+"/Login.js",params:{getAuthUser:true},method:"GET",success:Pman.Login.success,failure:Pman.Login.failure,scope:Pman.Login});
+},failure:function(C,B){this.authUser=-1;this.sending=false;var A=Pman.processResponse(C);if(Pman.Login.checkFails>2){Pman.Preview.disable();Roo.MessageBox.alert(_T["8391d964e04c0c30d9f19bf036136c8d"],A.errorMsg?A.errorMsg:_T["54242987801741c4105cfa0435d9912e"]);
+return;}Pman.Login.check.defer(1000,Pman.Login,[true]);return;},success:function(C,B){this.sending=false;var A=Pman.processResponse(C);if(!A.success){return this.failure(C,B);}if(!A.data||!A.data.id){return this.failure(C,B);}this.fillAuth(A.data);this.checkFails=0;
+Pman.onload();},fillAuth:function(au){this.startAuthCheck();this.authUserId=au.id;this.authUser=au;this.lastChecked=new Date();Pman.fireEvent("authrefreshed",au);Roo.state.Manager.set("Pman.Login.lang."+appNameShort,au.lang);this.switchLang(au.lang);if(this.authUserId<0){Roo.MessageBox.alert(_T["9eba57f4ad82997225a340c5c140a869"],_T["5d5717e963d28007da9511d1416cbc43"]);
+}},intervalID:false,lastChecked:false,startAuthCheck:function(){if(Pman.Login.intervalID){return false;}Pman.Login.intervalID=window.setInterval(function(){Pman.Login.check(false);},120000);},create:function(){if(this.dialog){return;}var A=this;this.dialog=new Roo.LayoutDialog(Roo.get(document.body).createChild({tag:"div"}),{autoCreated:true,title:_T["68156a5e398303b805bd96fbc6b1f8ee"],modal:true,width:350,height:230,shadow:true,minWidth:200,minHeight:180,closable:false,draggable:false,collapsible:false,resizable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}});
+this.dialog.addButton(_T["b2d0ea65f8ae06179a40d78e52b7833c"],function(){var n=A.form.findField("username").getValue();if(!n.length){Roo.MessageBox.alert(_T["8391d964e04c0c30d9f19bf036136c8d"],_T["9055d707d0388278ceb4f35426316c1b"]);return;}Roo.Ajax.request({url:baseURL+"/Login.js",params:{passwordRequest:n},method:"POST",success:function(D,C){var B=Pman.processResponse(D);
+if(!B.success){Roo.MessageBox.alert(_T["8391d964e04c0c30d9f19bf036136c8d"],B.errorMsg?B.errorMsg:_T["2409934e0552cdd76753d2c11005b6b5"]);return;}Roo.MessageBox.alert(_T["463c573d3aed3795e9e3145f10cd1416"],_T["de7b06c26e8b5361eb8e33d068dd2ce4"]);},failure:function(){Roo.MessageBox.alert(_T["8391d964e04c0c30d9f19bf036136c8d"],_T["2409934e0552cdd76753d2c11005b6b5"]);
+}});});this.dialog.addButton(_T["68156a5e398303b805bd96fbc6b1f8ee"],function(){Pman.Login.dialog.el.mask(_T["31cfba7708e9535c79660355d0f8accf"]);Pman.Login.form.doAction("submit",{url:baseURL+"/Login",method:"POST"});});this.layout=this.dialog.getLayout();
+this.layout.beginUpdate();this.form=new Roo.form.Form({labelWidth:100,listeners:{actionfailed:function(f,B){Pman.Login.dialog.el.unmask();Roo.MessageBox.alert(_T["8391d964e04c0c30d9f19bf036136c8d"],B.result.errorMsg?B.result.errorMsg:_T["c1b8242e54c06ad890a6a091195f7b8e"]);
+},actioncomplete:function(re,B){Roo.state.Manager.set("Pman.Login.username."+appNameShort,Pman.Login.form.findField("username").getValue());Roo.state.Manager.set("Pman.Login.lang."+appNameShort,Pman.Login.form.findField("lang").getValue());Pman.Login.fillAuth(B.result.data);
+Pman.Login.dialog.hide();if(Roo.get("loading-mask")){Roo.get("loading-mask").show();}Pman.onload();}}});this.form.add(new Roo.form.TextField({fieldLabel:_T["7e698d4c146d9eefd5dcd10552b18098"],name:"username",width:200,autoCreate:{tag:_T["23e3b3bf16c1b9ee0b448a20cde1d8a0"],type:_T["356c052df252f5f41bf445742c4a9e92"],size:_T["e5c7255d15759b64bbee6c623c299744"]}}),new Roo.form.TextField({fieldLabel:_T["3b9a78188b115fa00e2285cd1047a02e"],inputType:"password",name:"password",width:200,autoCreate:{tag:_T["23e3b3bf16c1b9ee0b448a20cde1d8a0"],type:_T["356c052df252f5f41bf445742c4a9e92"],size:_T["e5c7255d15759b64bbee6c623c299744"]},listeners:{specialkey:function(e,ev){if(ev.keyCode==13){Pman.Login.dialog.el.mask(_T["31cfba7708e9535c79660355d0f8accf"]);
+Pman.Login.form.doAction("submit",{url:baseURL+"/Login.json",method:"POST"});}}}}),new Roo.form.ComboBox({fieldLabel:_T["b2a3486b5105e365dae1a1796390ba42"],name:"langdisp",store:{xtype:"SimpleStore",fields:["lang","ldisp"],data:[["en","English"],["zh_HK","繁中"],["zh_CN","簡中"]]},valueField:"lang",hiddenName:"lang",width:200,displayField:"ldisp",typeAhead:false,editable:false,mode:"local",triggerAction:"all",emptyText:"Select a Language...",selectOnFocus:true,listeners:{select:function(cb,B,ix){Pman.Login.switchLang(B.data.lang);
+}}}));var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);Pman.Login.form.el.createChild({tag:"img",src:rootURL+"/Pman/"+appNameShort+"/templates/images/logo.gif",style:"margin-bottom: 10px;"},Pman.Login.form.el.dom.firstChild);
+var vp=this.dialog.getLayout().add("center",new Roo.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));this.layout.endUpdate();this.fireEvent("render",this);},resizeToLogo:function(){var sz=Roo.get(Pman.Login.form.el.query("img")[0]).getSize();
+if(!sz){this.resizeToLogo.defer(1000,this);return;}var w=Ext.lib.Dom.getViewWidth()-100;var h=Ext.lib.Dom.getViewHeight()-100;Pman.Login.dialog.resizeTo(Math.max(350,Math.min(sz.width+30,w)),Math.min(sz.height+200,h));Pman.Login.dialog.center();},show:function(A){if(this.disabled){return;
+}A=A||false;if(Pman.Login.authUserId<0){return;}if(Pman.Login.intervalID){window.clearInterval(Pman.Login.intervalID);Pman.Login.intervalID=false;}this.create();if(Roo.get("loading")){Roo.get("loading").remove();}if(Roo.get("loading-mask")){Roo.get("loading-mask").hide();
+}this.form.reset();this.dialog.modal=!A;this.dialog.show();this.dialog.el.unmask();this.resizeToLogo.defer(1000,this);this.form.setValues({"username":Roo.state.Manager.get("Pman.Login.username."+appNameShort,""),lang:Roo.state.Manager.get("Pman.Login.lang."+appNameShort,"en")});
+Pman.Login.switchLang(Roo.state.Manager.get("Pman.Login.lang."+appNameShort,""));if(this.form.findField("username").getValue().length>0){this.form.findField("password").focus();}else{this.form.findField("username").focus();}},logout:function(){window.onbeforeunload=function(){};
+Pman.Login.authUserId=-1;Roo.Ajax.request({url:baseURL+"/Login.html",params:{logout:1},method:"GET",failure:function(){Roo.MessageBox.alert(_T["8391d964e04c0c30d9f19bf036136c8d"],_T["b9f8e134e8143020e2eb596292c7c1d1"],function(){document.location=baseURL+"?ts="+Math.random();
+});},success:function(){Pman.Login.authUserId=-1;Pman.Login.checkFails=0;document.location=baseURL+"?ts="+Math.random();}});},switchLang:function(A){if(!A.length){return;}if(typeof (_T.en)=="undefined"){_T.en={};Roo.apply(_T.en,_T);}if(typeof (_T[A])=="undefined"){Roo.MessageBox.alert(_T["20f52c7354a3fd19843e600c53121d94"],_T["1ba0950dff36aebd0c55f3b195edcb11"]+A+")");
+return;}Roo.apply(_T,_T[A]);if(this.form){function B(E,D){var C=Pman.Login.form.findField(E).el.dom.parentNode.parentNode;if(C.getElementsByTagName("label").length){C=C.getElementsByTagName("label")[0];}else{C=C.parentNode.getElementsByTagName("label")[0];
+}C.innerHTML=D;}B("password",_T["3b9a78188b115fa00e2285cd1047a02e"]+":");B("username",_T["7e698d4c146d9eefd5dcd10552b18098"]+":");B("lang",_T["b2a3486b5105e365dae1a1796390ba42"]+":");this.dialog.setTitle(_T["68156a5e398303b805bd96fbc6b1f8ee"]);this.dialog.buttons[0].setText(_T["b2d0ea65f8ae06179a40d78e52b7833c"]);
+this.dialog.buttons[1].setText(_T["68156a5e398303b805bd96fbc6b1f8ee"]);}},inGroup:function(g){return this.authUser&&this.authUser.groups&&this.authUser.groups.indexOf(g)>-1;},isOwner:function(){return this.authUser&&this.authUser.company_id_comptype&&this.authUser.company_id_comptype=="OWNER";
+},i18nList:function(A,B){return Pman.I18n.listToNames(A,B);},i18n:function(B,A){return Pman.I18n.toName(B,A);}});
+Pman.Preview={frame:false,pdf:false,imgDiv:false,active:false,init:function(){if(this.frame){return;}if(Roo.isGecko){this.pdf=Ext.DomHelper.append(document.body,{id:"pdf-view",tag:"object",type:"application/pdf",data:"about:blank",width:200,height:200,style:"position:absolute;top:-1000;left:-1000; z-index:-100",cn:[{tag:"param",name:"src",value:"about:blank"}]},false);
+}this.imgDiv=Ext.DomHelper.append(document.body,{tag:"div",style:"position:absolute;top:-1000;left:-1000; z-index:-100;"+"overflow-x:hidden;overflow-y:scroll;width:200px; height: 200px;"});this.frame=Ext.DomHelper.append(document.body,{tag:"iframe",src:"about:blank",style:"position:absolute;top:-1000;left:-1000; z-index:-100;"+"width:1px; height: 1px;"});
+},config:false,onResize:function(){if(this.active){this.active.style.zIndex=this.activeCfg?this.activeCfg.zIndex:-100;}if(!this.config.previewRegion){return;}var A=this.config.previewRegion.el.getBox();if(A.width<10){return;}if(!this.active){return;}this.active.setAttribute("width",A.width);
+this.active.setAttribute("height",A.height);this.active.style.width=A.width+"px";this.active.style.height=A.height+"px";this.active.style.top=A.y+"px";this.active.style.left=A.x+"px";},unlink:function(){if(!this.config){return;}if(this.config.dialog){this.config.dialog.un("hide",this.onHide,this);
+}if(this.config.tab){this.config.tab.un("deactivate",this.onHide,this);}this.config.previewRegion.un("resized",this.onResize,this);this.config=false;},link:function(A){this.init();if(this.config){this.unlink();}this.config=A;if(this.config.dialog){this.config.dialog.on("hide",this.onHide,this);
+}if(this.config.tab){this.config.tab.on("deactivate",this.onHide,this);}this.config.previewRegion.on("resized",this.onResize,this);},removeActive:function(){if(!this.active){return;}this.active.style.left="-1000px";this.active.style.top="-1000px";this.active.style.width="200px";
+this.active.style.top="200px";this.active.style.zIndex=-100;this.active=false;},onHide:function(){if(!this.active){return;}this.removeActive();this.unlink();},showPdf:function(){this.removeActive();this.activeCfg.url=this.activeCfg.pdfurl;this.activeCfg.mimetype="application/pdf";
+this.load(this.activeCfg);},load:function(A){this.activeCfg=false;if(typeof (A)!="object"){alert("Preview Load only accepts object with url/mimetype/zIndex as loader");return;}this.activeCfg=Roo.apply({},A);var B=this.activeCfg.url;var C=this.activeCfg.mimetype;
+this.removeActive();switch(C){case "image/jpeg":var ps=this.config.previewRegion.el.getBox();this.imgDiv.innerHTML="<img src=\""+B+"\""+" width=\""+(ps.width-15)+"\""+" qtip=\""+_T["e4fe205ae80b87b90434e12e5e3a4c9b"]+"\""+" ext:width=\"100\""+" onclick=\"Pman.Preview.showPdf();\"/>";
+this.active=this.imgDiv;this.enable(this.activeCfg.zIndex);return;break;case "application/pdf":case "application/msword":case "application/vnd.oasis.opendocument.text":case "application/vnd.ms-excel":case "application/vnd.oasis.opendocument.spreadsheet":case "application/vnd.dwg":case "application/acad":case "application/x-acad":case "application/autocad_dwg":case "image/x-dwg":case "application/dwg":case "application/x-dwg":case "application/x-autocad":case "image/vnd.dwg":case "drawing/dwg":if(!B.match(/\.pdf$/)){B+=".pdf";
+}if(!Roo.isGecko){this.frame.src=B;this.active=this.frame;this.enable(this.activeCfg.zIndex);return;}this.pdf.setAttribute("data",B);this.active=this.pdf;this.enable(this.activeCfg.zIndex);return;default:this.frame.src=B;this.active=this.frame;this.enable(this.activeCfg.zIndex);
+return;}},disable:function(){if(!this.active){return;}this.disabled=true;this.active.style.zIndex=-100;if(!Roo.isGecko){this.frame.src="about:blank";}},enable:function(A){if(!this.active){return;}this.disabled=false;this.active.style.zIndex=A?A:10000;if(!Roo.isGecko&&this.activeCfg){this.frame.src=this.activeCfg.url;
+}this.onResize();},tmpStatus:false,tmpDisable:function(){if(this.disabled){this.tmpStatus=false;return;}this.tmpStatus=true;this.disable();},tmpEnable:function(){if(!this.tmpStatus){return;}this.tmpStatus=false;this.enable();}}
+Pman.Readers.Companies={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:["code","name","remarks",{name:"owner_id",type:"int"},"address","tel","fax","email",{name:"id",type:"int"},{name:"isOwner",type:"int"},{name:"logo_id",type:"int"},"background_color","comptype","ava_craft","url",{name:"main_office_id",type:"int"},{name:"created_by",type:"int"},{name:"created_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"updated_by",type:"int"},{name:"updated_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"logo_id_id",type:"int"},"logo_id_filename","logo_id_ontable",{name:"logo_id_onid",type:"int"},"logo_id_mimetype",{name:"logo_id_width",type:"int"},{name:"logo_id_height",type:"int"},{name:"logo_id_filesize",type:"int"},{name:"logo_id_displayorder",type:"int"},"logo_id_language",{name:"logo_id_parent_image_id",type:"int"},{name:"logo_id_created",type:"date",dateFormat:"Y-m-d H:i:s"},"logo_id_imgtype","logo_id_linkurl","logo_id_descript","logo_id_title",{name:"owner_id_id",type:"int"},{name:"owner_id_office_id",type:"int"},"owner_id_name","owner_id_phone","owner_id_fax","owner_id_email",{name:"owner_id_company_id",type:"int"},"owner_id_role",{name:"owner_id_active",type:"int"},"owner_id_remarks","owner_id_passwd",{name:"owner_id_owner_id",type:"int"},"owner_id_lang",{name:"owner_id_no_reset_sent",type:"int"},{name:"owner_id_project_id",type:"int"},"owner_id_action_type",{name:"main_office_id_id",type:"int"},{name:"main_office_id_company_id",type:"int"},"main_office_id_name","main_office_id_address","main_office_id_phone","main_office_id_fax","main_office_id_email","main_office_id_role"]};
+Pman.Readers.Events={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},"person_name",{name:"event_when",type:"date",dateFormat:"Y-m-d H:i:s"},"action","ipaddr",{name:"on_id",type:"int"},"on_table",{name:"person_id",type:"int"},"remarks",{name:"person_id_id",type:"int"},{name:"person_id_office_id",type:"int"},"person_id_name","person_id_phone","person_id_fax","person_id_email",{name:"person_id_company_id",type:"int"},"person_id_role",{name:"person_id_active",type:"int"},"person_id_remarks","person_id_passwd",{name:"person_id_owner_id",type:"int"},"person_id_lang",{name:"person_id_no_reset_sent",type:"int"},{name:"person_id_project_id",type:"int"},"person_id_action_type"]};
+Pman.Readers.Group_Members={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"group_id",type:"int"},{name:"id",type:"int"},{name:"user_id",type:"int"},{name:"group_id_id",type:"int"},"group_id_name",{name:"group_id_type",type:"int"},{name:"group_id_leader",type:"int"},{name:"user_id_id",type:"int"},{name:"user_id_office_id",type:"int"},"user_id_name","user_id_phone","user_id_fax","user_id_email",{name:"user_id_company_id",type:"int"},"user_id_role",{name:"user_id_active",type:"int"},"user_id_remarks","user_id_passwd",{name:"user_id_owner_id",type:"int"},"user_id_lang",{name:"user_id_no_reset_sent",type:"int"},{name:"user_id_project_id",type:"int"},"user_id_action_type"]};
+Pman.Readers.Group_Rights={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:["rightname",{name:"group_id",type:"int"},"AccessMask",{name:"id",type:"int"},{name:"group_id_id",type:"int"},"group_id_name",{name:"group_id_type",type:"int"},{name:"group_id_leader",type:"int"}]};
+Pman.Readers.Groups={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},"name",{name:"type",type:"int"},{name:"leader",type:"int"},{name:"leader_id",type:"int"},{name:"leader_office_id",type:"int"},"leader_name","leader_phone","leader_fax","leader_email",{name:"leader_company_id",type:"int"},"leader_role",{name:"leader_active",type:"int"},"leader_remarks","leader_passwd",{name:"leader_owner_id",type:"int"},"leader_lang",{name:"leader_no_reset_sent",type:"int"},{name:"leader_project_id",type:"int"},"leader_action_type"]};
+Pman.Readers.Images={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},"filename","ontable",{name:"onid",type:"int"},"mimetype",{name:"width",type:"int"},{name:"height",type:"int"},{name:"filesize",type:"int"},{name:"displayorder",type:"int"},"language",{name:"parent_image_id",type:"int"},{name:"created",type:"date",dateFormat:"Y-m-d H:i:s"},"imgtype","linkurl","descript","title",{name:"parent_image_id_id",type:"int"},"parent_image_id_filename","parent_image_id_ontable",{name:"parent_image_id_onid",type:"int"},"parent_image_id_mimetype",{name:"parent_image_id_width",type:"int"},{name:"parent_image_id_height",type:"int"},{name:"parent_image_id_filesize",type:"int"},{name:"parent_image_id_displayorder",type:"int"},"parent_image_id_language",{name:"parent_image_id_parent_image_id",type:"int"},{name:"parent_image_id_created",type:"date",dateFormat:"Y-m-d H:i:s"},"parent_image_id_imgtype","parent_image_id_linkurl","parent_image_id_descript","parent_image_id_title"]};
+Pman.Readers.Office={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},{name:"company_id",type:"int"},"name","address","phone","fax","email","role","company_id_code","company_id_name","company_id_remarks",{name:"company_id_owner_id",type:"int"},"company_id_address","company_id_tel","company_id_fax","company_id_email",{name:"company_id_id",type:"int"},{name:"company_id_isOwner",type:"int"},{name:"company_id_logo_id",type:"int"},"company_id_background_color","company_id_comptype","company_id_ava_craft","company_id_url",{name:"company_id_main_office_id",type:"int"},{name:"company_id_created_by",type:"int"},{name:"company_id_created_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"company_id_updated_by",type:"int"},{name:"company_id_updated_dt",type:"date",dateFormat:"Y-m-d H:i:s"}]};
+Pman.Readers.Person={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},{name:"office_id",type:"int"},"name","phone","fax","email",{name:"company_id",type:"int"},"role",{name:"active",type:"int"},"remarks","passwd",{name:"owner_id",type:"int"},"lang",{name:"no_reset_sent",type:"int"},{name:"project_id",type:"int"},"action_type",{name:"office_id_id",type:"int"},{name:"office_id_company_id",type:"int"},"office_id_name","office_id_address","office_id_phone","office_id_fax","office_id_email","office_id_role","company_id_code","company_id_name","company_id_remarks",{name:"company_id_owner_id",type:"int"},"company_id_address","company_id_tel","company_id_fax","company_id_email",{name:"company_id_id",type:"int"},{name:"company_id_isOwner",type:"int"},{name:"company_id_logo_id",type:"int"},"company_id_background_color","company_id_comptype","company_id_ava_craft","company_id_url",{name:"company_id_main_office_id",type:"int"},{name:"company_id_created_by",type:"int"},{name:"company_id_created_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"company_id_updated_by",type:"int"},{name:"company_id_updated_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"project_id_id",type:"int"},"project_id_name","project_id_remarks",{name:"project_id_owner_id",type:"int"},"project_id_code",{name:"project_id_active",type:"int"},"project_id_type",{name:"project_id_client_id",type:"int"},{name:"project_id_team_id",type:"int"},"project_id_file_location",{name:"project_id_open_date",type:"date",dateFormat:"Y-m-d"},{name:"project_id_open_by",type:"int"},"project_id_countries","project_id_languages",{name:"project_id_close_date",type:"date",dateFormat:"Y-m-d"},{name:"project_id_agency_id",type:"int"},{name:"owner_id_id",type:"int"},{name:"owner_id_office_id",type:"int"},"owner_id_name","owner_id_phone","owner_id_fax","owner_id_email",{name:"owner_id_company_id",type:"int"},"owner_id_role",{name:"owner_id_active",type:"int"},"owner_id_remarks","owner_id_passwd",{name:"owner_id_owner_id",type:"int"},"owner_id_lang",{name:"owner_id_no_reset_sent",type:"int"},{name:"owner_id_project_id",type:"int"},"owner_id_action_type"]};
+Pman.Readers.Projects={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},"name","remarks",{name:"owner_id",type:"int"},"code",{name:"active",type:"int"},"type",{name:"client_id",type:"int"},{name:"team_id",type:"int"},"file_location",{name:"open_date",type:"date",dateFormat:"Y-m-d"},{name:"open_by",type:"int"},"countries","languages",{name:"close_date",type:"date",dateFormat:"Y-m-d"},{name:"agency_id",type:"int"},"client_id_code","client_id_name","client_id_remarks",{name:"client_id_owner_id",type:"int"},"client_id_address","client_id_tel","client_id_fax","client_id_email",{name:"client_id_id",type:"int"},{name:"client_id_isOwner",type:"int"},{name:"client_id_logo_id",type:"int"},"client_id_background_color","client_id_comptype","client_id_ava_craft","client_id_url",{name:"client_id_main_office_id",type:"int"},{name:"client_id_created_by",type:"int"},{name:"client_id_created_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"client_id_updated_by",type:"int"},{name:"client_id_updated_dt",type:"date",dateFormat:"Y-m-d H:i:s"},"agency_id_code","agency_id_name","agency_id_remarks",{name:"agency_id_owner_id",type:"int"},"agency_id_address","agency_id_tel","agency_id_fax","agency_id_email",{name:"agency_id_id",type:"int"},{name:"agency_id_isOwner",type:"int"},{name:"agency_id_logo_id",type:"int"},"agency_id_background_color","agency_id_comptype","agency_id_ava_craft","agency_id_url",{name:"agency_id_main_office_id",type:"int"},{name:"agency_id_created_by",type:"int"},{name:"agency_id_created_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"agency_id_updated_by",type:"int"},{name:"agency_id_updated_dt",type:"date",dateFormat:"Y-m-d H:i:s"},{name:"team_id_id",type:"int"},"team_id_name",{name:"team_id_type",type:"int"},{name:"team_id_leader",type:"int"},{name:"open_by_id",type:"int"},{name:"open_by_office_id",type:"int"},"open_by_name","open_by_phone","open_by_fax","open_by_email",{name:"open_by_company_id",type:"int"},"open_by_role",{name:"open_by_active",type:"int"},"open_by_remarks","open_by_passwd",{name:"open_by_owner_id",type:"int"},"open_by_lang",{name:"open_by_no_reset_sent",type:"int"},{name:"open_by_project_id",type:"int"},"open_by_action_type",{name:"owner_id_id",type:"int"},{name:"owner_id_office_id",type:"int"},"owner_id_name","owner_id_phone","owner_id_fax","owner_id_email",{name:"owner_id_company_id",type:"int"},"owner_id_role",{name:"owner_id_active",type:"int"},"owner_id_remarks","owner_id_passwd",{name:"owner_id_owner_id",type:"int"},"owner_id_lang",{name:"owner_id_no_reset_sent",type:"int"},{name:"owner_id_project_id",type:"int"},"owner_id_action_type"]};
+Pman.Readers.I18n={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},"ltype","lkey","inlang","lval"]};Pman.Readers.Proftp_groups={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},{name:"grpid",type:"int"},"grpname","grpmembers"]};
+Pman.Readers.Translations={root:"data",totalProperty:"total",id:"id",xtype:"JsonReader",fields:[{name:"id",type:"int"},"module","tfile","tlang","tkey","tval"]};
+Pman.Dialog.Image={dialog:false,form:false,create:function(){if(this.dialog){return;}var A=this;this.dialog=new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:"div"}),{autoCreated:true,title:_T["180ab418d1431a5e3ab16412df46995c"],modal:true,width:500,height:140,shadow:true,minWidth:200,minHeight:180,closable:false,draggable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}});
+this.dialog.addKeyListener(27,this.dialog.hide,this.dialog);this.dialog.addButton(_T["584228d91d54c791da0c7b9f60eb0568"],this.dialog.hide,this.dialog);this.dialog.addButton(_T["e7cf748ba346b55abdcc4b23eee865f2"],this.save,this);this.layout=this.dialog.getLayout();
+this.layout.beginUpdate();this.form=new Ext.form.Form({labelWidth:150,fileUpload:true,listeners:{actionfailed:function(f,B){A.uploadComplete=true;A.dialog.el.unmask();if(B.type=="submit"){Ext.MessageBox.alert(_T["f63d2ff3c0824d9a6d914b023170a0e7"],_T["de7fa9da20484d1ee51e3e11385b106a"]);
+return;}Ext.MessageBox.alert(_T["f63d2ff3c0824d9a6d914b023170a0e7"],_T["6bb7047abac30e5f215a55ee1258d63e"]);},actioncomplete:function(f,B){A.uploadComplete=true;A.dialog.el.unmask();if(B.type=="load"){A.data=B.result.data;return;}if(B.type=="submit"){A.dialog.hide();
+if(A.callback){A.callback.call(this,B.result.data);}return;}}}});this.form.addxtype.apply(this.form,[{name:"UPLOAD_IDENTIFIER",xtype:"Hidden"},{xtype:"TextField",name:"imageUpload",fieldLabel:_T["6644290819b3cd82cd7a447b4f9082d9"],inputType:"file"},{name:"ontable",xtype:"Hidden"},{name:"onid",xtype:"Hidden"},{name:"imgtype",xtype:"Hidden"},{name:"post_max_size",xtype:"Hidden",value:"32M"},{name:"upload_max_filesize",xtype:"Hidden",value:"32M"}]);
+var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);var vp=this.dialog.getLayout().add("center",new Ext.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));this.layout.endUpdate();
+},_id:0,show:function(A,B){this.callback=B;this.create();this.form.reset();this.form.setValues(A);this.form.findField("UPLOAD_IDENTIFIER").setValue((new Date()*1)+""+Math.random());this.dialog.show();},save:function(){this.dialog.el.mask(_T["7e627bc5cadbc3aa73653b2e65eebf41"]);
+this.uploadComplete=false;this.form.doAction("submit",{url:baseURL+"/Roo/Images.html",method:"POST",params:{ts:Math.random()}});this.haveProgress=false,this.uploadProgress.defer(1000,this);},uploadComplete:false,haveProgress:false,uploadProgress:function(){if(!this.haveProgress){Roo.MessageBox.progress(_T["3b504c4d3b791c1aa278926f21482646"],_T["3b504c4d3b791c1aa278926f21482646"]);
+}if(this.uploadComplete){Roo.MessageBox.hide();return;}this.haveProgress=true;var B=this;var A=this.form.findField("UPLOAD_IDENTIFIER").getValue();Pman.request({url:baseURL+"/Core/UploadProgress.php",params:{id:A},method:"GET",success:function(C){if(B.uploadComplete){Roo.MessageBox.hide();
+return;}if(C){Roo.MessageBox.updateProgress(C.bytes_uploaded/C.bytes_total,Math.floor((C.bytes_total-C.bytes_uploaded)/1000)+"k remaining");}B.uploadProgress.defer(2000,B);},failure:function(C){}})}};
+Pman.Dialog.Office={dialog:false,form:false,create:function(){if(this.dialog){return;}this.dialog=new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:"div"}),{autoCreated:true,title:_T["7836ab6fe8fe6f6ec502b3108a13e21d"],modal:true,width:650,height:400,shadow:true,minWidth:200,minHeight:180,closable:false,draggable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}});
+this.dialog.addKeyListener(27,this.dialog.hide,this.dialog);this.dialog.addButton(_T["1832ff6f8f4dc04e11d8da18197bd04e"],this.dialog.hide,this.dialog);this.dialog.addButton(_T["09216d718e93d47e7fab400386e0e666"],this.save,this);this.layout=this.dialog.getLayout();
+this.layout.beginUpdate();var dg=Pman.Dialog.Office;this.form=new Ext.form.Form({labelWidth:250,listeners:{actionfailed:function(f,A){dg.dialog.el.unmask();Pman.standardActionFailed(f,A);},actioncomplete:function(f,A){dg.dialog.el.unmask();if(A.type=="load"){dg.data=A.result.data;
+return;}if(A.type=="submit"){dg.dialog.hide();if(dg.callback){dg.callback.call(this,A.result.data);}return;}}}});this.form.addxtype.apply(this.form,[{"name":"id",value:"",xtype:"Hidden"},{"name":"company_id",value:"",xtype:"Hidden"},{"name":"company_id_name",fieldLabel:_T["b41c4b23e06e87f60c5cb0bd5bf4de81"],value:"",xtype:"TextField",readOnly:true,width:300},{"name":"name",fieldLabel:_T["526fafd56ab833df1f4ffd447600a9d1"],value:"",allowBlank:false,qtip:_T["69424c2ba40b27522c5f582fbe4b754b"],xtype:"TextField",width:300},{"name":"address",fieldLabel:_T["1576472bc936da286e17816117c69800"],value:"",qtip:_T["c8805cab313fc29f3642f9a5c7f9aa64"],xtype:"TextArea",height:100,width:300},{"name":"phone",fieldLabel:_T["e726c3820bd60bc1c312fb8c51dc3642"],value:"",qtip:_T["085c2f603ebade12c9f292ef40fd6b07"],xtype:"TextField",width:300},{"name":"fax",fieldLabel:_T["85a92c56516f8b4fb28cef275e39aa59"],value:"",qtip:_T["4e53f9de03e95a51293bbd4c2518cc7d"],xtype:"TextField",width:300},{"name":"email",fieldLabel:_T["55d8a63eb4ad34aaf8a64e677a7ba02e"],value:"",qtip:_T["20c803184f4250311d36b34678a81e99"],xtype:"TextField",width:300}]);
+var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);var vp=this.dialog.getLayout().add("center",new Ext.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));this.layout.endUpdate();
+},_id:0,show:function(A,B){this.callback=B;this._id=A.id;this.create();this.form.reset();this.form.setValues(A);this.dialog.show();this.form.findField("name").focus();},save:function(){this.form.doAction("submit",{url:baseURL+"/Roo/Office.html",method:"POST",params:{_id:this._id,ts:Math.random()}});
+}};
+Pman.on("beforeload",function(){Pman.Dialog.Person=new Pman.Dialog.PersonEditor({type:"edit2",dialogConfig:{title:_T["3e8788f13c62d5400e2eef9ce61ff6d6"],height:400},itemList:["company_id_name_ro","office_id_name_ro","name","role","phone","fax","email","id","office_id","company_id","company_id_email","company_id_address","company_id_tel","company_id_fax"]});
+});
+Pman.Tab.GroupsList=function(A){Ext.apply(this,A);};Pman.Tab.GroupsList.prototype={id:false,grid:false,panel:false,getDialog:false,title:false,type:0,disabled:false,add:function(F,C){var B=this;var G=function(){B.refresh();};if(this.panel){F.getRegion(C).showPanel(this.panel);
+return;}var refreshCenterPanel=function(){var I=F.getRegion("center").getActivePanel();if(I&&I.controller){I.controller.refresh();return;}var H=I.id;if(!H){return;}Pman.Tab[H].refresh();};var frm=F.getRegion(C).getEl().createChild({tag:"div"});this.grid=new Ext.grid.Grid(frm,{id:B.id+"-groups",enableDrop:true,ddGroup:"groupDD",ds:new Ext.data.Store({proxy:new Ext.data.HttpProxy({url:baseURL+"/Roo/Groups.html",method:"GET"}),remoteSort:true,reader:Pman.Readers.Groups,sortInfo:{field:"name",direction:"ASC"},listeners:{beforeload:function(t,o){if(!o.params){o.params={};
+}o.params.type=B.type;},load:function(){var sm=B.grid.getSelectionModel();if(!sm.getSelections().length){sm.selectFirstRow();}refreshCenterPanel();},loadexception:Pman.loadException}}),sm:new Ext.grid.RowSelectionModel({singleSelect:true}),cm:new Ext.grid.ColumnModel([{id:B.id+"-name",header:_T["45e376f384cdb1f67a866700b892b3e8"],dataIndex:"name",sortable:true,width:100,renderer:function(v,x,r){if(r.data.id==-1){return "<b>"+_T["d5cd30d9a8889de9ad91d34e09da494b"]+"</b>";
+}if((r.data.id==0)&&(B.type==0)){return "<b>"+_T["8b2b7b9a1be82d2550e1d2bf71504f40"]+"</b>";}if((r.data.id==0)&&(B.type==2)){return "<b>"+_T["0534e1944a96427d47b562c494d85447"]+"</b>";}if(r.data.id==0){return "<b>"+_T["0b0e4ee0b6875cbaa307a8d7f3c3d7ee"]+"</b>";
+}if(v=="Administrators"){return "<b>"+_T["b9b270f938cabca10640a932c830a4ce"]+"</b>";}if(r.data.leader){return v+" ("+r.data.leader_name+")";}return v;}}]),autoExpandColumn:B.id+"-name",clicksToEdit:1,loadMask:true,listeners:{rowclick:function(g,ri,e){refreshCenterPanel();
+}}});this.panel=F.add(C,new Ext.GridPanel(this.grid,{fitToframe:true,fitContainer:true,title:B.title,id:B.id,background:true}));this.grid.render();new Ext.dd.DropTarget(B.grid.getView().mainBody,{ddGroup:"groupDD",copy:true,notifyOver:function(dd,e,I){var t=Roo.lib.Event.getTarget(e);
+var ri=B.grid.view.findRowIndex(t);var H=false;if(ri!==false){H=B.grid.getDataSource().getAt(ri).data;}var s=B.grid.getSelectionModel().getSelections();var K=s.length?s[0].data.id>0:false;var J=H&&H.id>0;if(K&&J){return this.dropNotAllowed;}if(!K&&!J){return this.dropNotAllowed;
+}if(K&&!J){return "x-dd-drop-ok-sub";}return "x-dd-drop-ok-add";},notifyDrop:function(dd,e,I){var t=Roo.lib.Event.getTarget(e);var ri=B.grid.view.findRowIndex(t);var H=false;if(ri!==false){H=B.grid.getDataSource().getAt(ri).data;}var s=B.grid.getSelectionModel().getSelections();
+var M=s.length?s[0].data.id>0:false;var L=H&&H.id>0;if(M&&L){return false;}if(!M&&!L){return false;}var K="add";if(M&&!L){K="sub";}var J=[];for(var i=0;i<I.selections.length;i++){J.push(I.selections[i].data.id);}Pman.request({url:baseURL+"/Core/GroupMembers.php",params:{action:K,group_id:K=="add"?H.id:s[0].data.id,type:B.type,user_ids:J.join(",")},method:"POST",success:function(N){G();
+},failure:function(){}});return true;}});var A=this.grid;var E=this.grid.getView().getHeaderPanel(true);this.toolbar=new Ext.Toolbar(E);var D=this.getDialog();this.toolbar.add({text:_T["982d7a1e24433e552a3d694a095f053e"],cls:"x-btn-text-icon",icon:Ext.rootURL+"images/default/tree/leaf.gif",menu:{items:[{text:_T["0f65f59038860dbf03201afab99fe7e1"],cls:"x-btn-text-icon",icon:Ext.rootURL+"images/default/dd/drop-add.gif",hidden:!Pman.hasPerm("Core.Groups","A"),handler:function(){D.show({id:0,type:B.type},G);
+}},{text:_T["0537a153a0e54447d83d2c8d094a03d1"],cls:"x-btn-text-icon",icon:Ext.rootURL+"images/default/tree/leaf.gif",hidden:!Pman.hasPerm("Core.Groups","E"),handler:function(){var s=A.getSelectionModel().getSelections();if(!s.length||(s.length>1)){Ext.MessageBox.alert(_T["081fcfe0460716e500eeab497d45d6b8"],s.length?_T["f845801a4be23199251c41e1c2ac5e98"]:_T["178044591ed0652d2b82b7f7eb90b22a"]);
+return;}if((s[0].data.name=="Administrators")||(s[0].data.name=="Default")){Ext.MessageBox.alert(_T["081fcfe0460716e500eeab497d45d6b8"],_T["075c26b58d3827f7726bb1eb7c2d13dc"]);return;}if(s.data.id<1){Ext.MessageBox.alert(_T["081fcfe0460716e500eeab497d45d6b8"],_T["075c26b58d3827f7726bb1eb7c2d13dc"]);
+return;}D.show(s[0].data,G);}},{text:_T["1eeb327bd294d207da46d9cfb93f9042"],cls:"x-btn-text-icon",icon:rootURL+"/Pman/templates/images/trash.gif",hidden:!Pman.hasPerm("Core.Groups","D"),handler:function(){var s=A.getSelectionModel().getSelections();for(var i=0;
+i<s.length;i++){if((s[i].data.id<1)||(s[i].data.name=="Administrators")){Ext.MessageBox.alert(_T["081fcfe0460716e500eeab497d45d6b8"],_T["2d481b48a578e9122e0cda91604a73b1"]);return;}}Pman.genericDelete(B,"Groups");}},"-",{text:_T["726e57af6b8966adfdcaa385105de4d1"],cls:"x-btn-text-icon",icon:rootURL+"/Pman/templates/images/view-refresh.gif",handler:function(){G();
+}}]}});this.panel.on("activate",function(){});},refresh:function(){this.grid.getDataSource().reload();}};
+Pman.Tab.PersonList=function(A){Ext.apply(this,A);};Pman.Tab.PersonList.prototype={id:"",type:0,title:false,hiddenColumns:false,itemDisplayName:false,permName:"Core.Person",getLeftSelections:function(){return [];},hideDelete:false,beforeload:function(t,o){alert("person list not configured");
+return false;var A=_this.getLeftSelections();if(A.length){o.params["query[in_group]"]=A[0].data.id;}o.params["query[name]"]=this.searchBox.getValue();o.params["query[type]"]=this.type;o.params["query[person_internal_only_all]"]=1;o.params["query[person_inactive]"]=this.showInActive?0:1;
+},columns:function(){alert("person list not configured");return false;return [this.c_name(),this.c_office_id_name(),this.c_role(),this.c_phone(),this.c_fax(),this.c_email(),this.c_active()]},dialog:function(){alert("person list not configured");return false;
+return Pman.Dialog.PersonStaff;},bulkAdd:function(){return false;},newDefaults:function(){alert("person list not configured");return false;return {id:0,company_id:Pman.Login.authUser.company_id,company_id_name:Pman.Login.authUser.company_id_name,company_id_address:Pman.Login.authUser.company_id_address,company_id_tel:Pman.Login.authUser.company_id_tel,company_id_fax:Pman.Login.authUser.company_id_fax};
+},parentLayout:false,showInActive:0,grid:false,panel:false,toolbar:false,paging:false,tab:false,refreshWestPanel:function(){var A=this.parentLayout.getRegion("west").getActivePanel();if(A&&A.controller){A.controller.paging.onClick("refresh");return;}if(!A||!A.id){return;
+}Pman.Tab[A.id].refresh();},refresh:function(){if(!this.paging){this.delayedCreate();}this.paging.onClick("refresh");},loadFirst:function(){if(!this.paging){this.delayedCreate();}this.paging.onClick("first");},add:function(C,B){var A=this;if(this.tab){C.getRegion(B).showPanel(this.panel);
+return;}this.parentLayout=C;this.layout=new Ext.BorderLayout(C.getEl().createChild({tag:"div"}),{center:{autoScroll:true,hideTabs:true}});this.tab=C.add(B,new Ext.NestedLayoutPanel(this.layout,{title:this.title,background:true,controller:this}));this.tab.on("activate",function(){A.delayedCreate();
+});},delayedCreate:function(){var C=this;if(this.grid){return;}var E=function(){C.refresh();};this.layout.beginUpdate();var A=this.layout.getRegion("center").getEl().createChild({tag:"div"});this.grid=new Ext.grid.Grid(A,{ddGroup:"groupDD",enableDrag:true,id:this.id+"-grid",ds:new Ext.data.Store({proxy:new Ext.data.HttpProxy({url:baseURL+"/Roo/Person.html",method:"GET"}),reader:Pman.Readers.Person,remoteSort:true,listeners:{beforeload:function(t,o){return C.beforeload(t,o);
+},loadexception:Pman.loadException},sortInfo:{field:"name",direction:"ASC"}}),cm:new Ext.grid.ColumnModel(this.columns()),autoExpandColumn:C.id+"-name",clicksToEdit:1,loadMask:true,listeners:{rowdblclick:function(g,ri,e){var s=g.getDataSource().getAt(ri).data;
+if(C.dialog()&&Pman.hasPerm(C.permName,"E")){C.dialog().show(s,E);}}}});this.panel=this.layout.add("center",new Ext.GridPanel(this.grid,{fitToframe:true,fitContainer:true,id:this.id,title:this.title||_T["25310235b726d71d9d0bc2fc903b9a3b"],controller:this}));
+this.grid.render();if(this.hiddenColumns){var cm=this.grid.getColumnModel();Roo.each(this.hiddenColumns,function(c){cm.setHidden(cm.getIndexByDataIndex(c),true);});}var D=this.grid.getView().getFooterPanel(true);this.paging=new Ext.PagingToolbar(D,this.grid.getDataSource(),{pageSize:25,displayInfo:true,displayMsg:_T["4788be05034a6a24e08add98ed12fddf"]+(this.itemDisplayName||_T["25310235b726d71d9d0bc2fc903b9a3b"])+_T["0a1ea6b8f312884c024a49ea271b6330"],emptyMsg:_T["f405b2cca36f62eb81fa563a0b7406ac"]+(this.itemDisplayName||_T["25310235b726d71d9d0bc2fc903b9a3b"])+_T["7bca1e8820519d2993ebabfa434007c9"]});
+var B=this.grid;this.toolbar=new Ext.Toolbar(this.grid.getView().getHeaderPanel(true));var tb=this.toolbar;if(this.parentLayout.getRegion("west")&&this.parentLayout.getRegion("west").panels.length){this.paging.add("<b><i><font color=\"red\">"+(this.type?_T["469845eeeb8c7f2983a5fc6550af4dc7"]:_T["d559132c96908612dd66163dbd532812"])+"</font></i></b>");
+}var C=this;if(this.permName=="Core.Staff"){this.paging.add("-",{text:_T["40c16e64d6bf564aa75d2287d06c9a7b"],pressed:false,enableToggle:true,toggleHandler:function(F,G){C.showInActive=(G?1:0);F.setText(G?_T["2bcbf24c822c1428b849349709d432b4"]:_T["40c16e64d6bf564aa75d2287d06c9a7b"]);
+E();}},"-");}this.searchBox=new Ext.form.TextField({name:"search",width:135,listeners:{specialkey:function(f,e){if(e.getKey()==13){E();}}}});var dg=C.dialog();tb.add({text:_T["39c8bb31d465dfc147324be427ace5e9"],cls:"x-btn-text-icon",icon:Ext.rootURL+"images/default/dd/drop-add.gif",hidden:!dg||(C.newDefaults()===false)||!Pman.hasPerm(this.permName,"A"),handler:function(){dg.show(C.newDefaults(),E);
+}},{text:_T["a89b59994ae0fe49d108d3e22d68a8f3"],cls:"x-btn-text-icon",icon:Ext.rootURL+"images/default/dd/drop-add.gif",hidden:!this.bulkAdd()||!Pman.hasPerm(this.permName,"A"),handler:function(){C.bulkAdd().show({id:0},E);}},{text:_T["d1ff8ffcb0bc971614aef7c0b5a07290"],cls:"x-btn-text-icon",icon:Ext.rootURL+"images/default/tree/leaf.gif",hidden:!dg||!Pman.hasPerm(this.permName,"E"),handler:function(){var s=B.getSelectionModel().getSelections();
+if(!s.length||(s.length>1)){Ext.MessageBox.alert(_T["bf5c8b4410513986dffc6d6d6f025c5f"],s.length?_T["8d7a86f0b9a3f7f52e7b49206b42f1ff"]:_T["f8eeb7a5fd0bed49c85e3664518a5e7c"]);return;}dg.show(s[0].data,E);}},{text:_T["022426919cf2c4cb91db4d37dbe5d24c"],cls:"x-btn-text-icon",icon:rootURL+"/Pman/templates/images/trash.gif",hidden:(this.permName!="Core.Staff")||!Pman.hasPerm(this.permName,"E"),handler:function(){var s=B.getSelectionModel().getSelections();
+if(!s.length){Ext.MessageBox.alert(_T["bf5c8b4410513986dffc6d6d6f025c5f"],_T["ecb1973f7aa6a900a49efa65dfc18da4"]);return;}var r=[];for(var i=0;i<s.length;i++){r.push(s[i].data.id);}B.getView().mainWrap.mask(_T["0c87cd7a6911dfa20a87e9073a4891f0"]);Ext.Ajax.request({url:baseURL+"/Roo/Person.html",method:"GET",params:{_toggleActive:r.join(",")},success:function(G){var F=Pman.processResponse(G);
+B.getView().mainWrap.unmask();if(!F.success){Ext.MessageBox.alert(_T["bf5c8b4410513986dffc6d6d6f025c5f"],F.errorMsg?F.errorMsg:_T["864c4e5c64245516e1fcdabaf49b8de1"]);return;}E();},failure:function(F){B.getView().mainWrap.unmask();Ext.MessageBox.alert(_T["bf5c8b4410513986dffc6d6d6f025c5f"],_T["864c4e5c64245516e1fcdabaf49b8de1"]);
+}});}},{text:_T["1984cf10277dee6c3ff92d27c3b05493"],cls:"x-btn-text-icon",hidden:(this.permName=="Core.Staff")||!Pman.hasPerm("Core.Person","D")||this.hideDelete,icon:rootURL+"/Pman/templates/images/trash.gif",handler:function(){Pman.genericDelete(C,"Person");
+}},"-","Search: ",this.searchBox,{icon:rootURL+"/Pman/templates/images/search.gif",cls:"x-btn-icon",qtip:_T["f128b31c31b3754f5792d2eefdca21d0"],handler:function(){C.grid.getSelectionModel().clearSelections();E();}},{icon:rootURL+"/Pman/templates/images/edit-clear.gif",cls:"x-btn-icon",qtip:_T["87472631093f63c722db73519eb9e4b9"],handler:function(){C.searchBox.setValue("");
+C.grid.getSelectionModel().clearSelections();E();}});this.layout.endUpdate();},c_project_id_code:function(A){A=A||{};return Roo.apply({header:_T["4d49b66bbfd392f5307e93c277054732"],dataIndex:"project_id_code",sortable:false,width:70,renderer:function(v,x,r){return String.format("<span qtip=\"{0}\">{1}</span>",r.data.action_type,v);
+}},A);},c_name:function(A){A=A||{};return Roo.apply({id:this.id+"-name",header:_T["aacd489f97738135f87d1c85be64536b"],dataIndex:"name",sortable:true,width:150},A);},c_company_id_comptype:function(A){A=A||{};return Roo.apply({header:_T["bd87244321a326daa26695ab4b721c7c"],dataIndex:"company_id_comptype",sortable:true,width:70},A);
+},c_company_id_name:function(A){A=A||{};return Roo.apply({header:_T["60c647263578176b102261a5ae1004a6"],dataIndex:"company_id_name",sortable:true,width:150,renderer:function(v,x,r){return String.format("{0}{1}{2}",v,r.data.office_id?" / ":"",r.data.office_id_name);
+}},A);},c_office_id_name:function(A){A=A||{};return Roo.apply({header:_T["3bb13cf053c9459ba5f2bad62a2e208b"],dataIndex:"office_id_name",sortable:true,width:150},A);},c_role:function(A){A=A||{};return Roo.apply({header:_T["118585dae50b38d2079b28afa5d768d6"],dataIndex:"role",sortable:true,width:100},A);
+},c_phone:function(A){A=A||{};return Roo.apply({header:_T["0bfc17408bdeecfce4652e09c3b90621"],dataIndex:"phone",sortable:true,width:70},A);},c_fax:function(A){A=A||{};return Roo.apply({header:_T["1ee4e8e2d1859ff63a7b58f29505249f"],dataIndex:"fax",sortable:true,width:70},A);
+},c_email:function(A){A=A||{};return Roo.apply({header:_T["42fcc3face9df26268d1c2bf30dcd747"],dataIndex:"email",sortable:true,width:150,renderer:function(v){return (v.length&&v.indexOf("@")>0)?String.format("<a href=\"mailto:{0}\">{0}</a>",v):v;}},A);},c_active:function(A){A=A||{};
+return Roo.apply({header:_T["54bf9f5699148960b91086f351cf159e"],dataIndex:"active",sortable:true,width:50,renderer:function(v){var B=v>0?"-checked":"";return "<img class=\"x-grid-check-icon"+B+"\" src=\""+Ext.BLANK_IMAGE_URL+"\"/>";}},A);}};
+Pman.PasswordChange={dialog:false,form:false,create:function(){if(this.dialog){return;}var A=this;this.dialog=new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:"div"}),{autoCreated:true,title:_T["eadd75daa6471a87eb75121dd5eab06a"],modal:true,width:500,height:160,shadow:true,resizable:false,closable:false,draggable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}});
+var B=function(C){Pman.Preview.tmpEnable();A.dialog.hide();if(A.callback){A.callback.call(this,C?C:false);}};this.dialog.addKeyListener(27,B,this);this.dialog.addButton(_T["9b6839c225da5cb93c3bf29720e0531d"],B,this);this.dialog.addButton(_T["f7c61a97b669d7f5128b51c8644c400c"],this.save,this);
+this.layout=this.dialog.getLayout();this.layout.beginUpdate();this.form=new Ext.form.Form({labelWidth:220,listeners:{actionfailed:function(f,C){A.dialog.el.unmask();if(C.failureType=="client"){Ext.MessageBox.alert(_T["db88368227b739ed12b165005f43d2c9"],_T["23b47796783d663d3113bde8469f9202"]);
+return;}if(C.type=="submit"){Ext.MessageBox.alert(_T["db88368227b739ed12b165005f43d2c9"],typeof (C.result.errorMsg)=="string"?C.result.errorMsg:_T["25092a9a028d282401e526d9252c734d"]);return;}Ext.MessageBox.alert(_T["db88368227b739ed12b165005f43d2c9"],_T["39b3f1da7208ad35ea991d47bb460b30"]);
+},actioncomplete:function(f,C){A.dialog.el.unmask();if(C.type=="submit"){B(C.data);return;}}}});this.form.addxtype.apply(this.form,[{name:"passwd1",fieldLabel:_T["1b6ed9a99ae0f49a874fab476d0e70c4"],value:"",allowBlank:false,inputType:"password",xtype:"SecurePass",width:220,imageRoot:rootURL+"/Pman/templates/images"},{name:"passwd2",fieldLabel:_T["6f52a45578b8376c688a75ddc7888122"],value:"",allowBlank:false,inputType:"password",xtype:"TextField",width:220},{name:"passwordReset",value:"",xtype:"Hidden"}]);
+var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);var vp=this.dialog.getLayout().add("center",new Ext.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));this.layout.endUpdate();
+},_id:0,show:function(A,B){this.callback=B;this.data=A;this.create();this.form.reset();this.form.setValues(A);Pman.Preview.tmpDisable();this.dialog.show();this.form.findField("passwd1").focus();},save:function(){var p1=this.form.findField("passwd1").getValue();
+var p2=this.form.findField("passwd2").getValue();if(!p1.length||!p2.length){Ext.MessageBox.alert(_T["db88368227b739ed12b165005f43d2c9"],_T["78a7430d961bec5b3d4759206ebc2b04"]);}if(p1!=p2){Ext.MessageBox.alert(_T["db88368227b739ed12b165005f43d2c9"],_T["a217bd43e7427e981bc8dbf18998faed"]);
+}this.form.doAction("submit",{url:baseURL+"/Login.html",method:"POST",params:{changePassword:true,ts:Math.random()}});}}
+Pman.Dialog.Projects={dialog:false,form:false,create:function(){if(this.dialog){return;}this.dialog=new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:"div"}),{autoCreated:true,title:_T["59222ad07bc6410bf27eab7d035b409d"],modal:true,width:450,height:450,shadow:true,minWidth:200,minHeight:180,closable:false,draggable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}});
+this.dialog.addKeyListener(27,this.dialog.hide,this.dialog);this.dialog.addButton(_T["0e8ccf88135bae007b5cff5837e3e197"],this.dialog.hide,this.dialog);this.dialog.addButton(_T["d825914fad6e57c9d1acac55bc74f464"],this.save,this);this.layout=this.dialog.getLayout();
+this.layout.beginUpdate();var dg=Pman.Dialog.Projects;this.form=new Ext.form.Form({labelWidth:100,listeners:{actionfailed:function(f,A){dg.dialog.el.unmask();Pman.standardActionFailed(f,A);},actioncomplete:function(f,A){dg.dialog.el.unmask();if(A.type=="load"){dg.data=A.result.data;
+return;}if(A.type=="submit"){dg.dialog.hide();if(dg.callback){dg.callback.call(this,A.result.data);}return;}}}});this.form.addxtype.apply(this.form,[{name:"code",fieldLabel:_T["f1a3e388543d7a8d39f1a3d4ade58b94"],value:"",allowBlank:false,qtip:_T["9384bc850b628f21d964769bd7d13e44"],xtype:"TextField",width:100},{name:"name",fieldLabel:_T["2e6569fe7187cf7b776eebf79012c19c"],value:"",allowBlank:true,qtip:_T["be3b8a3bb525b99922adf15223852b6a"],xtype:"TextField",width:300},{xtype:"ComboBox",name:"type_desc",selectOnFocus:true,qtip:_T["7ca882603340513c5a17a92e2ba98140"],fieldLabel:_T["7ca882603340513c5a17a92e2ba98140"],allowBlank:false,width:200,store:new Ext.data.SimpleStore({fields:["code","desc"],data:Pman.Tab.ProjectsMgr.getTypes()}),displayField:"desc",editable:false,valueField:"code",hiddenName:"type",typeAhead:true,forceSelection:true,mode:"local",triggerAction:"all"},{xtype:"ComboBoxAdder",fieldLabel:_T["ff40386a43ccfe9066f7ebe51992cd86"],name:"client_id_name",selectOnFocus:true,qtip:_T["720eb6ec8a30c82c92847a11ee6d32e6"],allowBlank:true,width:277,store:new Ext.data.Store({proxy:new Ext.data.HttpProxy({url:baseURL+"/Roo/Companies.html",method:"GET"}),reader:Pman.Readers.Companies,listeners:{loadexception:Pman.loadException}}),displayField:"name",valueField:"id",hiddenName:"client_id",typeAhead:true,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{name}</b> {address}","</div>"),queryParam:"query[name]",loadingText:_T["4a17dd69fb7066cf43bf7c5f3d9e4cc6"],listWidth:400,minChars:2,pageSize:20,listeners:{adderclick:function(){var cb=this;
+Pman.Dialog.Companies.show({id:0},function(A){cb.setFromData(A);});},blur:function(f){if(!f.el.getValue().length){this.setFromData({id:0,name:_T["bd58983405ed76181a8d0ce7223d2780"]});}}}},{xtype:"ComboBox",fieldLabel:_T["0699fc5c5d74dce96c828c6e578ece63"],name:"team_id_name",selectOnFocus:true,qtip:_T["45e0394905808bcc80c34202748ddb13"],allowBlank:true,width:300,store:new Ext.data.Store({proxy:new Ext.data.HttpProxy({url:baseURL+"/Roo/Groups.html",method:"GET"}),reader:Pman.Readers.Groups,listeners:{beforeload:function(g,o){o.params=o.params?o.params:{};
+o.params.type=1;o.params["query[group_pulldown]"]=1;},loadexception:Pman.loadException}}),displayField:"name",valueField:"id",hiddenName:"team_id",typeAhead:true,forceSelection:true,triggerAction:"all",queryParam:"query[name]",loadingText:_T["4a17dd69fb7066cf43bf7c5f3d9e4cc6"],minChars:2,listeners:{blur:function(f){if(!f.el.getValue().length){this.setFromData({id:0,name:_T["bd58983405ed76181a8d0ce7223d2780"]});
+}}}},{name:"file_location",fieldLabel:_T["b72ffe66d7fb5278bc886ee23dbda9fa"],value:"",qtip:_T["4206f45d33f6d7d12e9e7b6efc86e0de"],allowBlank:true,xtype:"TextField",width:300},{name:"remarks",fieldLabel:_T["59242789e33d13385e7775bc7421464e"],value:"",allowBlank:true,qtip:_T["0ebe06a05911b24af87a933ca81882a0"],xtype:"TextArea",width:300,height:100},{xtype:"FieldSet",legend:"Opened",style:"width:393px;padding:0 0 2 10;",items:[{name:"open_date",fieldLabel:_T["00f5ccf184f1ff533931bde4424040b2"],value:"",allowBlank:true,qtip:_T["b90aa2ba8fe6d79a85c11ef4034f1f86"],xtype:"DateField",altFormats:"Y-m-d|d/m/Y",width:100,format:"d/m/Y"},{xtype:"ComboBox",fieldLabel:_T["c2257f446d410ea7a44b2f3fd68baa4a"],name:"open_by_name",selectOnFocus:true,qtip:_T["5fcc9c08873869529a4c0f640c34b803"],allowBlank:true,width:250,store:new Ext.data.Store({proxy:new Ext.data.HttpProxy({url:baseURL+"/Roo/Person.html",method:"GET"}),reader:Pman.Readers.Person,listeners:{beforeload:function(st,o){o.params.company_id=Pman.Login.authUser.company_id*1;
+},loadexception:Pman.loadException}}),displayField:"name",valueField:"id",hiddenName:"open_by",typeAhead:true,forceSelection:true,doForce:function(){if(this.el.dom.value.length>0){this.el.dom.value=this.lastSelectionText===undefined?_T["bd58983405ed76181a8d0ce7223d2780"]:this.lastSelectionText;
+this.applyEmptyText();if(!this.el.dom.value.length){this.setFromData({id:0,name:"----"});}}},triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{name}</b> {role}","</div>"),queryParam:"query[name]",loadingText:_T["4a17dd69fb7066cf43bf7c5f3d9e4cc6"],listWidth:300,minChars:2,pageSize:20}]},{name:"id",value:"",xtype:"Hidden"}]);
+var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);var vp=this.dialog.getLayout().add("center",new Ext.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));this.layout.endUpdate();
+},_id:0,show:function(A,B){this.callback=B;this._id=A.id;this.data=A;this.create();this.form.reset();this.form.setValues(A);if(A.id){this.form.findField("client_id").setFromData({id:A.client_id,name:A.client_id_name});this.form.findField("team_id").setFromData({id:A.team_id,name:A.team_id_name});
+this.form.findField("open_by").setFromData({id:A.open_by,name:A.open_by_name});}this.dialog.show();},save:function(){this.form.doAction("submit",{url:baseURL+"/Roo/Projects.html",method:"POST",params:{_id:this._id,ts:Math.random()}});}};
+Pman.Dialog.Companies=new Roo.util.Observable({events:{"beforerender":true,show:true,beforesave:true},dialog:false,form:false,callback:false,create:function(){if(this.dialog){return;}this.dialog=new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:"div"}),{autoCreated:true,title:_T["daed45fe377199115ee46b87eb340dcc"],modal:true,width:750,height:400,shadow:true,minWidth:200,minHeight:180,collapsible:false,closable:false,draggable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}});
+this.dialog.addKeyListener(27,this.dialog.hide,this.dialog);this.dialog.addButton(_T["e35c34d957d7aebd0c9e37aa77f50b70"],this.dialog.hide,this.dialog);this.dialog.addButton(_T["59c001255d821a2e12e8fb705dba9fea"],this.save,this);this.layout=this.dialog.getLayout();
+this.layout.beginUpdate();var A=this;this.form=new Ext.form.Form({labelWidth:150,fileUpload:true,listeners:{actionfailed:function(f,B){A.dialog.el.unmask();Pman.standardActionFailed(f,B);},actioncomplete:function(f,B){A.dialog.el.unmask();if(B.type=="load"){A.data=B.result.data;
+var C=A.data.isOwner||!Pman.Login.isOwner()?"disable":"enable";if(A.form.findField("comptype")){A.form.findField("comptype")[C]();}return;}if(B.type=="submit"){A.dialog.hide();if(A.callback){A.callback.call(this,B.result.data);}return;}}}});this.form.addxtype.apply(this.form,this.getFormFields());
+this.fireEvent("beforeRender",this);var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);var vp=this.dialog.getLayout().add("center",new Ext.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));
+this.layout.endUpdate();},show:function(A,B){this.callback=B;this._id=A.id?A.id:0;this.create();this.data=A;this.form.reset();if(A._fetch){this.dialog.show();this.dialog.el.mask(_T["5f679f3c301a24b3f538a9766ee3ae6e"]);this.form.doAction("load",{url:baseURL+"/Roo/Companies.html",method:"GET",params:{_id:this._id,_ts:Math.random()}});
+this.fireEvent("show");return;}else{this.form.setValues(A);}this.dialog.show();if(A.isOwner||!Pman.Login.isOwner()){this.dialog.setTitle(_T["1f0d43f377b93713beb48cbaca0e4401"]);if(this.form.findField("comptype")){this.form.findField("comptype").disable();
+}}else{this.dialog.setTitle(A.id?_T["4cf24f0f74944b39fd350182d5e15817"]:_T["ce9ba64bb3f29723e000efb2e80abb8e"]);if(this.form.findField("comptype")){this.form.findField("comptype").enable();}}this.fireEvent("show");},save:function(){this.form.fileUpload=this.form.findField("imageUpload")?true:false;
+this.fireEvent("beforesave");this.form.doAction("submit",{url:baseURL+"/Roo/Companies.html",method:"POST",params:{_id:this._id,ts:Math.random()}});},comptypeList:function(){return [["CONSULTANT",_T["650deecbb5e829066db9b03be1125a1c"]],["CLIENT",_T["59bfcea58d8c79f4a8cc2ce8256a167a"]],["CONTRACTOR",_T["692e49978c615ffee8b37ed3a8ef2a12"]],];
+},comptypeListToString:function(v){if(!v.length){return "";}if(v==_T["e3aa17d446c7005272762934b3b1e1a0"]){return _T["3fbd4316b2e824257633036893085545"];}var a=this.comptypeList();var A="";Roo.each(a,function(ar){if(ar[0]==v){A=ar[1];return false;}});return A;
+},getFormFields:function(){return [{xtype:"Column",width:500,items:[this.c_code(),this.c_comptype_name(),this.c_name(),this.c_tel(),this.c_fax(),this.c_email(),this.c_address(),this.c_remarks(),]},{xtype:"Column",width:200,labelAlign:"top",items:[this.c_background_color(),this.c_image_edit()]},this.c_isOwner(),this.c_id()];
+},c_code:function(){return {name:"code",fieldLabel:_T["857adf078513b5f11f815595aa0f9fd1"],value:"",allowBlank:false,qtip:_T["75d069b37c5159f5acb5d01d10a2d9a3"],xtype:"TextField",width:100}},c_comptype_name:function(){return {fieldLabel:"Type",disabled:Pman.Login.isOwner()?false:true,name:"comptype_name",xtype:"ComboBox",allowBlank:false,qtip:"Select Company type",width:200,xns:Roo.form,listWidth:250,store:{xtype:"SimpleStore",fields:["val","desc"],data:this.comptypeList()},displayField:"desc",valueField:"val",hiddenName:"comptype",typeAhead:false,editable:false,triggerAction:"all",emptyText:_T["81cbd120755795f72b127151e540cde5"],selectOnFocus:true}},c_name:function(){return {name:"name",fieldLabel:_T["37b6f9357707805a4612ebc166766ee2"],value:"",allowBlank:true,qtip:_T["d0845cdf23eb01488ec78802847e0273"],xtype:"TextField",width:300}},c_tel:function(){return {name:"tel",fieldLabel:_T["f111792776dd00af4e9575dffce62c41"],value:"",allowBlank:true,qtip:_T["7512ebcca5961d7894b501b6b0556c36"],xtype:"TextField",width:300}},c_fax:function(){return {name:"fax",fieldLabel:_T["5595a13ebb30e328ffb5b6def210a94c"],value:"",allowBlank:true,qtip:_T["73fe964a2d78700ea90ec792a87cb425"],xtype:"TextField",width:300}},c_email:function(){return {name:"email",fieldLabel:_T["4e3ed651f76a84604309db4a263b8e44"],value:"",allowBlank:true,qtip:_T["5caf4f1f1ea765a217064568800b9eee"],xtype:"TextField",width:300}},c_address:function(){return {name:"address",fieldLabel:_T["7688941a47dfb4d4edaaf460f81d69ab"],value:"",allowBlank:true,qtip:_T["bcde687f68818bdff785998f3f4b4dcc"],xtype:"TextArea",height:70,width:300}},c_remarks:function(){return {name:"remarks",fieldLabel:_T["7931e6a8fdc03aeb23619c11057cfb46"],value:"",allowBlank:true,qtip:_T["978731b3f7cb08990f958c25b4cc9702"],xtype:"TextArea",height:40,width:300}},c_background_color:function(){return {xtype:"ColorField",name:"background_color",fieldLabel:_T["4c63cd35411e0bfe84d30f523cf6b93a"]}},c_image_view:function(){var A=this;
+return {xtype:"FieldSetEx",name:"image-view",collapseGroup:"companies-image",value:0,labelWidth:100,expanded:true,style:"width:420px;",legend:_T["9c24ec3378fb01fb54d25c2075d3293d"],items:[{xtype:"DisplayImage",name:"logo_id",fieldLabel:"Logo Image",width:300,height:50,renderer:function(v){return v?String.format("<img src=\"{0}\" height=\"{1}\">",baseURL+"/Images/"+v+"/"+A.data.logo_id_filename,Math.min(this.height,A.data.logo_id_height)):_T["31e77d71bd68053a7d6fcd4bc974af6a"];
+}}]}},c_image_edit:function(){var A=this;return {name:"logo_id",fieldLabel:_T["9c24ec3378fb01fb54d25c2075d3293d"],value:"",allowBlank:true,style:"border: 1px solid #ccc;",xtype:"DisplayImage",width:170,height:170,addTitle:_T["8ffc3bf05859510e6dc4613b607cdcbe"],icon:Roo.rootURL+"images/default/dd/drop-add.gif",handler:function(){var _t=this;
+Pman.Dialog.Image.show({onid:A.data.id,ontable:"Companies",imgtype:"-LOGO"},function(B){if(B){_t.setValue(B.id);}});},renderer:function(v){if(!v){return _T["0e671bf5ff1cf6b299f895f78678121b"]+"<BR/>";}return String.format("<img src=\"{0}\" width=\"150\">",baseURL+"/Images/Thumb/150x150/"+v+"/logo.jpg");
+}};},c_image_change:function(){return {xtype:"FieldSetEx",collapseGroup:"companies-image",name:"image-change",value:0,labelWidth:100,expanded:false,style:"width:420px;",legend:_T["490679f6791d65bc9998cadb629c7053"],items:[{xtype:"TextField",name:"imageUpload",fieldLabel:_T["f5978f4e5815e0516744069dd287e5d9"],inputType:"file"}]}},c_isOwner:function(){return {name:"isOwner",value:"",xtype:"Hidden"}},c_id:function(){return {name:"id",value:"",xtype:"Hidden"}}});
+
+Pman.on("beforeload",function(){Pman.Dialog.PersonNew=new Pman.Dialog.PersonEditor({type:"new",dialogConfig:{title:_T["aacd89f134545118f60a671de60913d3"],height:350},itemList:["company_id_name","office_id_name","name","role","phone","fax","email","project_id_fs","id","company_id_email","company_id_address","company_id_tel","company_id_fax","project_id_addto"]});
+});
+Pman.on("beforeload",function(){Pman.Dialog.PersonEdit=new Pman.Dialog.PersonEditor({type:"edit",dialogConfig:{title:_T["bc619e5bc0e08070f5aea669b1afdba1"],height:350},itemList:["company_id_name","office_id_name","name","role","phone","fax","email","passwd1","passwd2","id","company_id_email","company_id_address","company_id_tel","company_id_fax"]});
+});
+Pman.on("beforeload",function(){Pman.Dialog.PersonStaff=new Pman.Dialog.PersonEditor({type:"staff",dialogConfig:{title:_T["386f61f04d35fedb1ab564f275a0cc37"]},itemList:["office_id_name","name","role","phone","fax","email_req","passwd1","passwd2","id","office_id","company_id","active","company_id_email","company_id_address","company_id_tel","company_id_fax"]});
+});
+Pman.Dialog.PersonEditor=function(A){Roo.apply(this,A);};Pman.Dialog.PersonEditor.prototype={itemList:false,dialogConfig:false,type:"",itemTypes:false,dialog:false,form:false,layout:false,callback:false,_id:false,data:false,create:function(){if(this.dialog){return;
+}var A=this;this.dialog=new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:"div"}),Roo.apply({autoCreated:true,title:"Edit Contact Details",modal:true,width:530,height:300,shadow:true,minWidth:200,minHeight:180,closable:false,draggable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}},this.dialogConfig));
+this.dialog.addKeyListener(27,this.dialog.hide,this.dialog);if(this.itemList.indexOf("save_send")>-1){this.dialog.addButton(_T["c5f95205dd78ae006d052009aa6142f8"],this.saveSend,this);}this.dialog.addButton(_T["687a326482448749613f378d040f6ef6"],this.dialog.hide,this.dialog);
+this.dialog.addButton(_T["7033b8924378a2098ecf784128d96125"],this.save,this);this.layout=this.dialog.getLayout();this.layout.beginUpdate();this.form=new Ext.form.Form({labelWidth:120,listeners:{actionfailed:function(f,B){A.dialog.el.unmask();Pman.standardActionFailed(f,B);
+},actioncomplete:function(f,B){A.dialog.el.unmask();if(B.type=="load"){A.data=B.result.data;}if((B.type=="load")||(B.type=="setdata")){var C=A.data;if(A.form.findField("company_id")&&A.form.findField("company_id").setFromData){A.form.findField("company_id").setFromData(C.company_id?{id:C.company_id,name:C.company_id_name,remarks:C.company_id_remarks,address:C.company_id_address,tel:C.company_id_tel,fax:C.company_id_fax,email:C.company_id_email}:{id:0,name:""});
+}if(A.form.findField("office_id")&&A.form.findField("office_id").setFromData){A.form.findField("office_id").setFromData(C.office_id?{id:C.office_id,name:C.office_id_name,remarks:C.office_id_remarks,address:C.office_id_address,tel:C.office_id_tel,fax:C.office_id_fax,email:C.office_id_email}:{id:0,name:""});
+}if(A.form.findField("project_id")){A.form.findbyId("project_id_fs").setExpand(C.project_id?true:false);A.form.findField("project_id").setFromData(C.project_id?{id:C.project_id,code:C.project_id_code}:{id:0,code:""});}if(this.type=="staff"){A.form.findField("passwd1").allowBlank=false;
+A.form.findField("passwd2").allowBlank=false;if(C.id>0){A.form.findField("passwd1").allowBlank=true;A.form.findField("passwd2").allowBlank=true;}}return;}if(B.type=="submit"){A.dialog.hide();if(A.callback){A.callback.call(this,B.result.data);}if(A.sendAfterSave){B.result.data.rawPasswd=A.form.findField("passwd1").getValue();
+A.sendIntro([B.result.data],_T["98ca94191386d0d2cd58bd272d1df5d7"]);}return;}}}});this.loadItemTypes();Roo.each(this.itemList,function(il){if(typeof (il)!="object"){A.form.addxtype(A.itemTypes[il]);return true;}A.form.addxtype(Roo.apply(il,A.itemTypes[il.name]));
+});var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);var vp=this.dialog.getLayout().add("center",new Ext.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));this.layout.endUpdate();
+},loadItemTypes:function(){var A=this;this.itemTypes={company_id_name_ro:{name:"company_id_name",fieldLabel:_T["92e1985e19c2bb5d9556ac7ba52d5a7a"],value:"",xtype:"TextField",readOnly:true,width:300},company_id_name:{xtype:"ComboBoxAdder",fieldLabel:_T["92e1985e19c2bb5d9556ac7ba52d5a7a"],name:"company_id_name",selectOnFocus:true,qtip:_T["276038b1ea02816633ab56c087ab5e8b"],allowBlank:false,width:300,store:{xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/Roo/Companies.html",method:"GET"},reader:Pman.Readers.Companies,listeners:{beforeload:function(st,o){o.params.isOwner=0;
+},loadexception:Pman.loadException},sortInfo:{field:"name",direction:"ASC"}},displayField:"name",valueField:"id",hiddenName:"company_id",typeAhead:true,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{name}</b> {address}","</div>"),queryParam:"query[name]",loadingText:_T["4b59409465457ad433c029640bf1a2c5"],listWidth:400,minChars:2,pageSize:20,listeners:{adderclick:function(){var cb=this;
+Pman.Dialog.Companies.show({id:0},function(B){cb.setFromData(B);});}}},office_id_name_ro:{name:"office_id_name",fieldLabel:_T["be407624d99fa1d3edd7ff59c079dd62"],value:"",xtype:"TextField",readOnly:true,width:300},office_id_name:{xtype:"ComboBoxAdder",fieldLabel:_T["b41f06c5d4aa97be01660b5033f3c0b9"],name:"office_id_name",selectOnFocus:true,qtip:_T["99667c31cbee3c1649a9abfba6f76f5f"],allowBlank:true,width:300,store:{xtype:"Store",proxy:{xtype:"HttpProxy",url:baseURL+"/Roo/Office.html",method:"GET"},reader:Pman.Readers.Office,listeners:{beforeload:function(st,o){var B=A.form.findField("company_id").getValue();
+o.params.company_id=B;},loadexception:Pman.loadException},sortInfo:{field:"name",direction:"ASC"}},listeners:{adderclick:function(){var cb=this;var B=false;var C=false;if(A.type=="new"){C=A.form.findField("company_id").lastData;if(!C.id){Ext.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["e81e0305bf7b9c0bff38b1bd4113a94b"]);
+return false}B={company_id:C.id,company_id_name:C.name,address:C.address,phone:C.tel,fax:C.fax,email:C.email};}else{C=A.data;B={company_id:C.company_id,company_id_name:C.company_id_name,address:C.company_id_address,phone:C.company_id_tel,fax:C.company_id_fax,email:C.company_id_email}}Pman.Dialog.Office.show(B,function(D){cb.setFromData(D);
+});},beforequery:function(qe){var B=A.form.findField("company_id").getValue();if(B<1){Ext.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["e81e0305bf7b9c0bff38b1bd4113a94b"]);return false;}}},displayField:"name",valueField:"id",hiddenName:"office_id",typeAhead:true,forceSelection:true,triggerAction:"all",tpl:new Ext.Template("<div class=\"x-grid-cell-text x-btn button\">","<b>{name}</b> {address}","</div>"),queryParam:"query[name]",loadingText:_T["4b59409465457ad433c029640bf1a2c5"],listWidth:400,minChars:2,pageSize:20},name:{name:"name",fieldLabel:_T["43a33d905d2c47dcd5afccb8d6c5c9ec"],value:"",allowBlank:false,qtip:_T["801f9098abec829acfaad24d9c38acf1"],xtype:"TextField",width:300},role:{name:"role",fieldLabel:_T["976cb754f8a3120a0d8ddecc7dad70b3"],value:"",allowBlank:true,qtip:_T["36e08fc5b447ea57d5f9801a0a594de8"],xtype:"TextField",width:300},phone:{name:"phone",fieldLabel:_T["8ecda72b47a4d87945396f1deb3a4e2b"],value:"",allowBlank:true,qtip:_T["60c2576c3bd6fce9593dfafa60d5dc71"],xtype:"TextField",width:300},fax:{name:"fax",fieldLabel:_T["6eab94585302a1eb047d8ad46a822fe1"],value:"",allowBlank:true,qtip:_T["bbc9b7422ae486331486a0734c399109"],xtype:"TextField",width:300},email:{name:"email",fieldLabel:_T["fef6c4502e830f3cb17ceda089079d08"],value:"",allowBlank:true,qtip:_T["b9b189c9b68fd2072e2937f60042e970"],xtype:"TextField",width:300},bulklist:{name:"bulklist",fieldLabel:_T["598d3e15de6c0edc42bbb12bba56848c"],value:"",allowBlank:false,qtip:_T["56270c6137713c24a973c4239ef10a8c"],xtype:"TextArea",width:300,height:200},email_req:{name:"email",fieldLabel:_T["fef6c4502e830f3cb17ceda089079d08"],value:"",allowBlank:false,qtip:_T["b9b189c9b68fd2072e2937f60042e970"],xtype:"TextField",width:300},passwd1:{name:"passwd1",fieldLabel:_T["024116eeefc851698f4381072c88c988"],value:"",allowBlank:true,inputType:"password",xtype:"SecurePass",width:220,imageRoot:rootURL+"/Pman/templates/images"},passwd2:{name:"passwd2",fieldLabel:_T["9ea81314e83737179ff499c00215e349"],value:"",allowBlank:true,inputType:"password",xtype:"TextField",width:220},project_id_fs:{xtype:"FieldSetEx",name:"project_id_fs",value:0,labelWidth:100,expanded:false,style:"width:420px;",legend:_T["28d4e53cb89a8406eaacfece36ecfbea"],items:[Pman.Std.project_id({width:300,fieldLabel:_T["b5506f1d5c8fcd78b22b830ce30a377f"],allowBlank:true}),{xtype:"ComboBox",name:"action_type_str",selectOnFocus:true,qtip:_T["fac109c69eeb67ebda3c5e40393bcb9b"],fieldLabel:_T["82c0f8b8dd0cb58b397ee9d6f633749e"],allowBlank:true,width:50,store:new Ext.data.SimpleStore({fields:["code","desc"],data:[["ACTION_REQUIRED",_T["035ee8612761bb1546093a1b22451b67"]],["NOTIFY",_T["4545094571d2bd9ce3dfc20783cf3dbc"]]]}),displayField:"desc",editable:false,valueField:"code",hiddenName:"action_type",value:"ACTION_REQUIRED",forceSelection:true,mode:"local",triggerAction:"all"}]},id:{name:"id",value:"",xtype:"Hidden"},save_send:{name:"_save_send",value:0,xtype:"Hidden"},active:{name:"active",value:1,xtype:"Hidden"},company_id:{name:"company_id",value:"",xtype:"Hidden"},company_id_email:{name:"company_id_email",value:"",xtype:"Hidden"},company_id_address:{name:"company_id_address",value:"",xtype:"Hidden"},company_id_tel:{name:"company_id_tel",value:"",xtype:"Hidden"},company_id_fax:{name:"company_id_fax",value:"",xtype:"Hidden"},project_id_addto:{name:"project_id_addto",value:"",xtype:"Hidden"}};
+},saveSend:function(bt,e){this.save(bt,e,1)},sendAfterSave:0,save:function(bt,e,A){this.sendAfterSave=A||0;if(this.form.findField("bulklist")){this.saveBulk();return;}if(!this.form.findField("company_id").getValue()){Ext.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["4e8097f84abcc6d92ca69656d0e94024"]);
+return;}if(this.form.findField("passwd1")){var p1=this.form.findField("passwd1").getValue();var p2=this.form.findField("passwd2").getValue();if(this.sendAfterSave&&!p1.length){Ext.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["3a2644a946cf95a21e5890507232305f"]);
+return;}if(Pman.Login.authUser.id<0&&!p1.length){Ext.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["c9f36f7b1c27b424e71ce6c66a2f000e"]);return;}if(p1.length||p2.length){if(p1!=p2){Ext.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["f202ec7143eb64a7694663d5d795972b"]);
+return;}}}if(this.form.findField("project_id")){if(!this.form.findbyId("project_id_fs").expanded){this.form.findField("project_id").setFromData({id:0,code:""});}}this.dialog.el.mask(_T["b57f7c3a947d7a7a24dcce08a1f789ec"]);this.form.doAction("submit",{url:baseURL+"/Roo/Person.html",method:"POST",params:{_id:this._id,ts:Math.random()}});
+},show:function(A,B){this.callback=B;this._id=A.id;this.data=A;this.create();this.form.reset();if(A._fetch){this.dialog.show();this.dialog.el.mask(_T["ecb6cc539899477d30b822eab4f51b57"]);this.form.doAction("load",{url:baseURL+"/Roo/Person.html",method:"GET",params:{_id:this._id,_ts:Math.random()}});
+return;}else{this.form.setValues(A);}this.form.fireEvent("actioncomplete",this.form,{type:"setdata",data:A});this.dialog.show();},saveBulk:function(){if(!this.form.findField("company_id").getValue()){Roo.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["6c755092c6556392d8f8589ea57ed32e"]);
+return;}var A=[];var B=this;Roo.MessageBox.confirm(_T["f81f0fdf4c6384f98a5d1f49ffd0ebe3"],_T["0734055957ed2deb78318855e001f072"],function(yn){var pw=1;if(yn!="yes"){pw=0;}Roo.each(B.form.findField("bulklist").getValue().split(_T["2b80fb0dc406c89322d30ed0c0f6150b"]),function(v){if(!v.length||!v.replace(new RegExp(" ","g"),"").length){return;
+}A.push({id:0,email:v,company_id:B.form.findField("company_id").getValue(),office_id:B.form.findField("office_id").getValue(),active:1,_create:1,_createPasswd:pw})});if(!A.length){Roo.MessageBox.alert(_T["7825faf6d798725b4f9c36122dc0d78f"],_T["453b606630064afeccae473d15cb21f1"]);
+return;}B.dialog.hide();B.sendIntro(A,_T["ffe42f94e27e5228d3d2320e16dfb61b"],B.callback)});},sendIntro:function(ar,A,D){var i=0;Roo.MessageBox.show({title:_T["d4efe6bd99e2f9dca237692425cd1e37"],msg:A,width:350,progress:true,closable:false});var C=this;var B=function(){if(i==ar.length){Roo.MessageBox.hide();
+Roo.MessageBox.alert(_T["78800f89af27b724063900f2ac603ea8"],_T["4f53be722b07293542247cc405232a69"]+A);if(D){D.call(this,false);}return;}Roo.MessageBox.updateProgress((i+1)/ar.length,A+_T["b3d5fbd734ec40cdb88c7e544b737e57"]+ar[i].email);var c=ar[i];i++;Pman.request({url:baseURL+"/Core/SendIntro.html",method:"POST",params:c,success:function(F,E){B();
+},failure:function(){Roo.MessageBox.show({title:_T["d4efe6bd99e2f9dca237692425cd1e37"],msg:A,width:350,progress:true,closable:false});B();}});};B();}};
+Pman.Dialog.Document_Types={dialog:false,form:false,create:function(){if(this.dialog){return;}this.dialog=new Ext.LayoutDialog(Ext.get(document.body).createChild({tag:"div"}),{autoCreated:true,title:_T["9566c872f5eb3606aff77e92ef404f6f"],modal:true,width:650,height:250,shadow:true,minWidth:200,minHeight:180,closable:false,draggable:false,center:{autoScroll:false,titlebar:false,hideTabs:true,closeOnTab:true,alwaysShowTabs:false}});
+this.dialog.addKeyListener(27,this.dialog.hide,this.dialog);this.dialog.addButton(_T["918b8aa8008529245b10c94d04e201c6"],this.dialog.hide,this.dialog);this.dialog.addButton(_T["7b0411b72ad383c3e2260d2293b0e2f7"],this.save,this);this.layout=this.dialog.getLayout();
+this.layout.beginUpdate();var dg=Pman.Dialog.Document_Types;this.form=new Ext.form.Form({labelWidth:250,listeners:{actionfailed:function(f,A){dg.dialog.el.unmask();Pman.standardActionFailed(f,A);},actioncomplete:function(f,A){dg.dialog.el.unmask();if(A.type=="load"){dg.data=A.result.data;
+return;}if(A.type=="submit"){dg.dialog.hide();if(dg.callback){dg.callback.call(this,A.result.data);}return;}}}});this.form.addxtype.apply(this.form,[{name:"code",fieldLabel:_T["3856b4848e0006d06445a3ec0026e6b9"],value:"",allowBlank:false,qtip:_T["ba960e685bbb3f9c913365a52e998454"],xtype:"TextField",width:100},{name:"name",fieldLabel:_T["04c4d9039b04ae1bb4143edcd3310cc3"],value:"",allowBlank:true,qtip:_T["16fdbf7788088cd5e4251adddf31957e"],xtype:"TextField",width:300},{name:"remarks",fieldLabel:_T["ff98eddf5a2bfb7ab13af0efe685783b"],value:"",allowBlank:true,qtip:_T["cfa368a58af37baf0ff74f80a9d7f192"],xtype:"TextArea",height:100,width:300},{name:"id",value:"",xtype:"Hidden"}]);
+var ef=this.dialog.getLayout().getEl().createChild({tag:"div"});ef.dom.style.margin=10;this.form.render(ef.dom);var vp=this.dialog.getLayout().add("center",new Ext.ContentPanel(ef,{autoCreate:true,width:250,maxWidth:250,fitToFrame:true}));this.layout.endUpdate();
+},_id:0,show:function(A,B){this.callback=B;this._id=A.id?A.id:0;this.create();this.form.reset();this.form.setValues(A);this.dialog.show();},save:function(){this.form.doAction("submit",{url:baseURL+"/Roo/Document_Types.html",method:"POST",params:{_id:this._id,ts:Math.random()}});
+}};
diff --git a/compiled/_translation_.js b/compiled/_translation_.js
new file mode 100644 (file)
index 0000000..bb0efcf
--- /dev/null
@@ -0,0 +1,308 @@
+
+"Pman.js" : {
+        "" : "",
+        " of " : " of ",
+        "Error" : "Error",
+        "Logout" : "Logout",
+        "Confirm" : "Confirm",
+        "Deleting" : "Deleting",
+        " (clean up) " : " (clean up) ",
+        "Add New Item" : "Add New Item",
+        "Error Sending" : "Error Sending",
+        "Error Deleting" : "Error Deleting",
+        "Error download" : "Error download",
+        "Please wait..." : "Please wait...",
+        "invalid in_out" : "invalid in_out",
+        "Change Password" : "Change Password",
+        "Building Interface " : "Building Interface ",
+        "Problem Loading Data" : "Problem Loading Data",
+        "Building Interface..." : "Building Interface...",
+        "Error loading details" : "Error loading details",
+        "Loading Document details" : "Loading Document details",
+        "Connection timed out sending" : "Connection timed out sending",
+        "Select at least one Row to delete" : "Select at least one Row to delete",
+        "Please Correct all the errors in red" : "Please Correct all the errors in red",
+        "Are you sure you want to delete that?" : "Are you sure you want to delete that?",
+        "You are Logged in as <b>{0} ({1})</b>" : "You are Logged in as <b>{0} ({1})</b>",
+        "Saving failed = fix errors and try again" : "Saving failed = fix errors and try again",
+        "Problem Connecting to Server - please try again." : "Problem Connecting to Server - please try again.",
+        "Closing this window will loose changes, are you sure you want to do that?" : "Closing this window will loose changes, are you sure you want to do that?"
+},
+"Pman.Std.js" : {
+        "To" : "To",
+        "Type" : "Type",
+        "Project" : "Project",
+        "Sent To" : "Sent To",
+        "Searching..." : "Searching...",
+        "Enter Sent To" : "Enter Sent To",
+        "Select Office" : "Select Office",
+        "Select Project" : "Select Project",
+        "Office / Department" : "Office / Department",
+        "Select Document Type" : "Select Document Type",
+        "Select an address to add." : "Select an address to add."
+},
+"Pman.I18n.js" : {
+        "Country" : "Country",
+        "Currency" : "Currency",
+        "Language" : "Language",
+        "Country(s)" : "Country(s)",
+        "Language(s)" : "Language(s)",
+        "Searching..." : "Searching...",
+        "Select Country" : "Select Country",
+        "Select Currency" : "Select Currency",
+        "Select Language" : "Select Language",
+        "Select a country to add." : "Select a country to add.",
+        "Select a language to add." : "Select a language to add."
+},
+"Pman.Login.js" : {
+        "20" : "20",
+        "text" : "text",
+        "Error" : "Error",
+        "Login" : "Login",
+        "Sorry" : "Sorry",
+        "input" : "input",
+        "Notice" : "Notice",
+        "Warning" : "Warning",
+        "Language" : "Language",
+        "Password" : "Password",
+        "Logging in" : "Logging in",
+        "Email Address" : "Email Address",
+        "Forgot Password" : "Forgot Password",
+        "Fill in your email address" : "Fill in your email address",
+        "Language not available yet (" : "Language not available yet (",
+        "Problem Requesting Password Reset" : "Problem Requesting Password Reset",
+        "Error logging out. - continuing anyway." : "Error logging out. - continuing anyway.",
+        "Login failed - communication error - try again." : "Login failed - communication error - try again.",
+        "Error getting authentication status. - try reloading" : "Error getting authentication status. - try reloading",
+        "Please check you email for the Password Reset message" : "Please check you email for the Password Reset message",
+        "This is an open system - please set up a admin user with a password." : "This is an open system - please set up a admin user with a password.",
+        "Error getting authentication status. - try reloading, or wait a while" : "Error getting authentication status. - try reloading, or wait a while"
+},
+"Pman.Preview.js" : {
+        "Click to view PDF" : "Click to view PDF"
+},
+"Pman.Dialog.Image.js" : {
+        "Save" : "Save",
+        "Error" : "Error",
+        "Cancel" : "Cancel",
+        "Sending" : "Sending",
+        "Uploading" : "Uploading",
+        "Upload Image or File" : "Upload Image or File",
+        "Error loading details" : "Error loading details",
+        "Upload Image or  File" : "Upload Image or  File",
+        "Saving failed = fix errors and try again" : "Saving failed = fix errors and try again"
+},
+"Pman.Dialog.Office.js" : {
+        "fax" : "fax",
+        "Save" : "Save",
+        "Email" : "Email",
+        "Phone" : "Phone",
+        "Cancel" : "Cancel",
+        "Address" : "Address",
+        "Company" : "Company",
+        "Enter fax" : "Enter fax",
+        "Enter name" : "Enter name",
+        "Enter email" : "Enter email",
+        "Enter phone" : "Enter phone",
+        "Enter address" : "Enter address",
+        "Office / Department / Sub Comp. Name" : "Office / Department / Sub Comp. Name",
+        "Edit Office / Department / Sub Company" : "Edit Office / Department / Sub Company"
+},
+"Pman.Dialog.Person.js" : {
+        "Edit Contact Details" : "Edit Contact Details"
+},
+"Pman.Tab.GroupsList.js" : {
+        "Add" : "Add",
+        "Edit" : "Edit",
+        "Name" : "Name",
+        "Error" : "Error",
+        "Delete" : "Delete",
+        "Reload" : "Reload",
+        "All Staff" : "All Staff",
+        "Everybody" : "Everybody",
+        "Select a Row" : "Select a Row",
+        "Adminstrators" : "Adminstrators",
+        "Manage Groups" : "Manage Groups",
+        "Not in a Group" : "Not in a Group",
+        "Select only one Row" : "Select only one Row",
+        "You can not delete that group" : "You can not delete that group",
+        "You can not rename that group" : "You can not rename that group",
+        "All Staff (Default Permissions)" : "All Staff (Default Permissions)"
+},
+"Pman.Tab.PersonList.js" : {
+        "Add" : "Add",
+        "Fax" : "Fax",
+        "No " : "No ",
+        "Edit" : "Edit",
+        "Name" : "Name",
+        "Email" : "Email",
+        "Error" : "Error",
+        "Phone" : "Phone",
+        "Staff" : "Staff",
+        " found" : " found",
+        "Active" : "Active",
+        "Delete" : "Delete",
+        "Search" : "Search",
+        "Project" : "Project",
+        "Sending" : "Sending",
+        "Bulk Add" : "Bulk Add",
+        "Displaying " : "Displaying ",
+        "Company Type" : "Company Type",
+        "Reset Search" : "Reset Search",
+        "Select a Row" : "Select a Row",
+        "Error Sending" : "Error Sending",
+        "Toogle Active" : "Toogle Active",
+        "Hide old staff" : "Hide old staff",
+        "Office / Dept." : "Office / Dept.",
+        "Show old staff" : "Show old staff",
+        "Role / Position" : "Role / Position",
+        "Company / Office" : "Company / Office",
+        " {0} - {1} of {2}" : " {0} - {1} of {2}",
+        "Select People Row" : "Select People Row",
+        "Select only one Row" : "Select only one Row",
+        "Drag person to add or remove from team" : "Drag person to add or remove from team",
+        "Drag person to add or remove from group" : "Drag person to add or remove from group"
+},
+"Pman.PasswordChange.js" : {
+        "Save" : "Save",
+        "Error" : "Error",
+        "Cancel" : "Cancel",
+        "New Password " : "New Password ",
+        "Change Password" : "Change Password",
+        "Error loading details" : "Error loading details",
+        "Passwords do not match" : "Passwords do not match",
+        "Enter Passwords in both boxes" : "Enter Passwords in both boxes",
+        "Please Correct all the errors" : "Please Correct all the errors",
+        "New Password (type again to confirm)" : "New Password (type again to confirm)",
+        "Saving failed = fix errors and try again" : "Saving failed = fix errors and try again"
+},
+"Pman.Dialog.Projects.js" : {
+        "" : "",
+        "By" : "By",
+        "Code" : "Code",
+        "Date" : "Date",
+        "Save" : "Save",
+        "Team" : "Team",
+        "Cancel" : "Cancel",
+        "Client" : "Client",
+        "Remarks" : "Remarks",
+        "Select Team" : "Select Team",
+        "Edit Project" : "Edit Project",
+        "Project Name" : "Project Name",
+        "Project type" : "Project type",
+        "Searching..." : "Searching...",
+        "File Location" : "File Location",
+        "Select Client" : "Select Client",
+        "Enter Date Opened" : "Enter Date Opened",
+        "Enter Project Code" : "Enter Project Code",
+        "Enter Project Name" : "Enter Project Name",
+        "Enter Project Remarks" : "Enter Project Remarks",
+        "Select Person Who opened" : "Select Person Who opened",
+        "Where are the files stored?" : "Where are the files stored?"
+},
+"Pman.Dialog.Companies.js" : {
+        "fax" : "fax",
+        "Save" : "Save",
+        "Email" : "Email",
+        "OWNER" : "OWNER",
+        "Phone" : "Phone",
+        "Cancel" : "Cancel",
+        "Client" : "Client",
+        "Address" : "Address",
+        "Loading" : "Loading",
+        "Remarks" : "Remarks",
+        "Consultant" : "Consultant",
+        "Contractor" : "Contractor",
+        "Enter code" : "Enter code",
+        "Logo Image" : "Logo Image",
+        "Add Company" : "Add Company",
+        "Select Type" : "Select Type",
+        "Company Name" : "Company Name",
+        "Edit Company" : "Edit Company",
+        "System Owner" : "System Owner",
+        "Upload Image" : "Upload Image",
+        "Enter Address" : "Enter Address",
+        "Enter remarks" : "Enter remarks",
+        "Edit Companies" : "Edit Companies",
+        "Enter fax Number" : "Enter fax Number",
+        "Background Colour" : "Background Colour",
+        "No Image Attached" : "No Image Attached",
+        "Add / Change Image" : "Add / Change Image",
+        "Change / Add Image" : "Change / Add Image",
+        "Enter Company Name" : "Enter Company Name",
+        "Enter Phone Number" : "Enter Phone Number",
+        "No Image Available" : "No Image Available",
+        "Enter Email Address" : "Enter Email Address",
+        "Your Company Details" : "Your Company Details",
+        "Company ID (for filing Ref.)" : "Company ID (for filing Ref.)"
+},
+"Pman.Dialog.PersonNew.js" : {
+        "New Contact Details" : "New Contact Details"
+},
+"Pman.Dialog.PersonEdit.js" : {
+        "Edit Contact Details" : "Edit Contact Details"
+},
+"Pman.Dialog.PersonStaff.js" : {
+        "Add / Edit Staff" : "Add / Edit Staff"
+},
+"Pman.Dialog.PersonEditor.js" : {
+        "No" : "No",
+        "\n" : "\n",
+        " : " : " : ",
+        "Fax" : "Fax",
+        "Yes" : "Yes",
+        "Done" : "Done",
+        "Save" : "Save",
+        "Email" : "Email",
+        "Error" : "Error",
+        "Phone" : "Phone",
+        "Cancel" : "Cancel",
+        "Office" : "Office",
+        "Company" : "Company",
+        "Done - " : "Done - ",
+        "Loading" : "Loading",
+        "Project" : "Project",
+        "Sending" : "Sending",
+        "Enter fax" : "Enter fax",
+        "Enter name" : "Enter name",
+        "Action Type" : "Action Type",
+        "Enter email" : "Enter email",
+        "Contact Name" : "Contact Name",
+        "Searching..." : "Searching...",
+        "Send Welcome" : "Send Welcome",
+        "New Password " : "New Password ",
+        "Select Office" : "Select Office",
+        "Please wait..." : "Please wait...",
+        "Select Company" : "Select Company",
+        "Action Required" : "Action Required",
+        "Role / Position" : "Role / Position",
+        "Select a Company" : "Select a Company",
+        "Enter phone Number" : "Enter phone Number",
+        "No addresses found" : "No addresses found",
+        "Office / Department" : "Office / Department",
+        "Enter email addresse" : "Enter email addresse",
+        "Enter Role / Position" : "Enter Role / Position",
+        "Passwords do not match" : "Passwords do not match",
+        "Send Introduction Mail" : "Send Introduction Mail",
+        "Select An Company First" : "Select An Company First",
+        "Select the Company Name" : "Select the Company Name",
+        "Sending Welcome Message" : "Sending Welcome Message",
+        "Email address (one per line)" : "Email address (one per line)",
+        "Password (type again to confirm)" : "Password (type again to confirm)",
+        "Creating Account / Sending Welcome" : "Creating Account / Sending Welcome",
+        "Send Welcome Messages and Generate Passwords?" : "Send Welcome Messages and Generate Passwords?",
+        "Always File Messages from this Person in Project" : "Always File Messages from this Person in Project",
+        "You must create a password for the admin account" : "You must create a password for the admin account",
+        "You must create a password to send introduction mail" : "You must create a password to send introduction mail"
+},
+"Pman.Dialog.Document_Types.js" : {
+        "Code" : "Code",
+        "Save" : "Save",
+        "Cancel" : "Cancel",
+        "Remarks" : "Remarks",
+        "Enter code" : "Enter code",
+        "Document Type" : "Document Type",
+        "Enter remarks" : "Enter remarks",
+        "Edit Document Type" : "Edit Document Type",
+        "Enter Document Type" : "Enter Document Type"
+},
\ No newline at end of file
diff --git a/core.css b/core.css
new file mode 100644 (file)
index 0000000..a429984
--- /dev/null
+++ b/core.css
@@ -0,0 +1,469 @@
+
+
+
+.logoblock {
+    background-color: #f8ecb2;
+}
+.x-grid-row .x-grid-col-Companies-Company_Name {
+    white-space: pre;
+}
+.x-grid-row .x-grid-td-FaxArchive-Details,
+.x-grid-row .x-grid-col-Directory-Directory_Address {
+    white-space: normal;
+}
+
+
+.x-grid-row-selected .x-grid-check-icon-toggle,
+.x-grid-check-icon-checked {
+    background:transparent url(/roojs1/images/default/menu/chk-sprite.gif) no-repeat scroll 0 -16px;
+    height:16px;
+    width:16px;
+}
+.x-grid-check-icon-toggle,
+.x-grid-check-icon {
+    background:transparent url(/roojs1/images/default/menu/chk-sprite.gif) no-repeat scroll 0 0;
+    height:16px;
+    width:16px;
+}
+.loading-indicator {
+    font-size:12px;
+    height:28px;
+}
+.loading-indicator {
+    background-position:left top;
+    background-repeat:no-repeat;
+    font-size:8pt;
+    height:18px;
+    padding-left:20px;
+    text-align:left;
+}
+#loading {
+    background:#fff;
+    border:1px solid #6593CF;
+    left:40%;
+    padding:2px;
+    position:absolute;
+    text-align:center;
+    top:40%;
+    width:250px;
+    
+    z-index:20001;
+    font-family:tahoma,arial,helvetica;
+}
+
+/** - add button next to combo box (of type ComboAdder) */
+.x-form-adder,
+.x-form-textfield-adder, 
+.x-form-textfield-minus
+{
+    background:transparent url(/roojs1/images/default/dd/drop-add.gif) no-repeat scroll 0 0;
+    border-style:none none solid;
+    
+    cursor:pointer;
+    height:21px;
+    position:absolute;
+    top:2;
+    width:17px;
+    margin-left: 20px;
+} 
+.x-form-textfield-adder
+{
+    margin-left: 3px;
+} 
+.x-form-textfield-minus
+{
+    background:transparent url(/roojs1/images/default/dd/drop-sub.gif) no-repeat scroll 0 0;
+    margin-left: 23px;
+}
+
+
+.x-date-menu .x-menu-list {
+    width: 200px;
+}
+
+/* Select distribution list - make pointer a hand */
+#distgrid-Documents_In .x-grid-row td,
+#distgrid-Documents_Out .x-grid-row td,
+#grid-Group_Members .x-grid-row td,
+#grid-Group_Rights .x-grid-row td
+{
+    cursor: pointer;
+}
+
+#headerInformation {
+    clear:none;
+    color:#244;
+    font-size:12px;
+    font-family:arial,tahoma,helvetica,sans-serif;
+    position:absolute;
+    right:210px;
+    top:6px;
+}
+
+#headerInformation-company-logo {
+   
+}
+#headerInformation-applogo {
+    position:absolute;
+    right:0px;
+}
+    
+.pman-details-view {
+    padding : 0x;
+}
+.pman-details-view-header {
+    padding: 2px; 
+    padding-left: 5px;
+    background: #ddd;
+    font-weight: bold;
+    -moz-user-focus:normal;
+    -x-system-font:none;
+    font-family:arial,tahoma,helvetica,sans-serif;
+    font-size:11px;
+    font-size-adjust:none;
+    font-stretch:normal;
+    font-style:normal;
+    font-variant:normal;
+    font-weight:normal;
+    line-height:13px;
+    outline-color:-moz-use-text-color;
+    outline-style:none;
+    outline-width:medium;
+    vertical-align:top;
+    white-space:nowrap;
+    
+    
+}
+/*
+.pman-details-view td {
+    padding : 10px;
+}
+*/
+.pman-details-tbl td {
+    padding: 1px;
+    white-space : normal;
+}
+.pman-details-view-remarks  {
+    margin: 0px 4px;
+}
+.pman-details-view-remark {
+    border-bottom:3px dotted #CCC;
+    padding-top:5px;
+}
+
+
+.pman-details-view-remark-header {
+    background-color : #f8f8f8;
+    display: block;    
+}
+
+.pman-details-view-remark-date {
+    display: inline;
+    float: right;
+    color: #999;
+}
+.pman-details-view-remark-to {
+    clear:none;
+    display:inline;
+    float:left;
+    font-weight:bold;
+}
+
+.pman-details-view-remark-body {
+    padding: 2px 0px 13px 0px;
+    clear: left;
+    border-top: 1px dotted #ccc;
+    white-space: normal;
+   /* width: 200px; */
+}
+            
+.pman-details-style,  .pman-details-style td {
+    font-family:arial,tahoma,helvetica,sans-serif;
+    font-size:11px;
+    font-size-adjust:none;
+    font-style:normal;
+    font-variant:normal;
+    font-weight:normal;
+    line-height:13px;
+     
+}       
+/* slightly ligher disabled */
+.x-item-disabled {
+    opacity:0.9;
+}  
+
+.x-tabs-wrap {
+    padding-top: 0px;
+}
+.x-tabs-wrap .x-toolbar {
+    padding-top : 0px;
+    padding-bottom : 0px;
+}
+/*
+#distgrid-DocumentsCirc_In .x-grid-header,
+#distgrid-DocumentsCirc_Out .x-grid-header 
+{
+    display:none;
+}
+*/
+/* status icon on inbox */
+.x-grid-col-Documents_Wip-locked_by .x-grid-cell-text,
+.x-grid-col-Unread-status_str .x-grid-cell-text,
+.x-grid-col-Inbox-status_str .x-grid-cell-text {
+    padding: 1px;
+}
+.x-strikethrough .x-grid-cell-text {
+    text-decoration: line-through;
+    color: #ccc;
+}
+.x-doc-closed .x-grid-cell-text {
+    color: #999;
+}
+
+/* override forms so they are a bit tighter */
+.x-form-label-top .x-form-element {
+    padding:0;
+}
+
+/*--------- timesheet -------*/
+.x-grid-td-ts_item .x-grid-cell-inner {
+    overflow: visible;
+}
+.x-grid-col-ts_clear .x-grid-cell-text {
+    padding: 1px;
+}
+
+
+
+.p-email-need-filing .x-toolbar {
+    
+    background: #f66 none no-repeat scroll 0 0;
+}
+.p-preview-remarks {
+    font-family:arial,tahoma,helvetica,sans-serif;
+    font-size:11px;
+    font-size-adjust:none;
+    font-style:normal;
+    font-variant:normal;
+    font-weight:normal;
+    line-height:13px;
+    white-space:nowrap;
+}
+/** ------ email adder ---- */
+.p-cblist-item {
+    display: table-cell; 
+    background: #e0ecff none no-repeat scroll 0 0;
+    float: left;
+    height: 18px;
+    -moz-border-radius: 2px;
+    margin: 2px;
+    float: left
+    
+    font-family:arial,tahoma,helvetica,sans-serif;
+    font-size:11px;
+    font-size-adjust:none;
+    font-style:normal;
+    font-variant:normal;
+    font-weight:normal;
+    
+}
+.p-cblist-item div
+{
+    display: table;
+    float: left;
+    margin: 2px;
+    margin-left: 5px;
+}
+.p-cblist-item img
+{
+   margin-left: 5px;
+   background:transparent url(../mailAddClose.gif) no-repeat scroll 0 0;
+   cursor: pointer;
+}
+.p-cblist-cb 
+{
+    float:left;
+}
+
+.p-cblist-grp
+{
+    padding: 2px;
+    border: 1px solid #e0ecff;
+    display: table;
+}
+   
+   /** ---- more kludges? --- */
+/* was clear none for some reason... dealflow changed this back? to both... */   
+.x-form-column .x-form-clear-left
+{
+    clear: both;
+}
+   
+   
+.p-thumb{
+       background: #ddd;
+       padding: 3px;
+    border: 2px solid #ddd;
+    
+}
+.x-view-selected .p-thumb {
+    border: 2px solid #66c;
+}
+
+/*
+.p-thumb img {
+       height: 100px;
+       width: 200px;
+}
+*/
+.p-thumb-wrap{
+       float: left;
+       margin: 4px;
+       margin-right: 0;
+       padding: 5px;
+       font-family:arial,tahoma,helvetica,sans-serif;
+    font-size:11px;
+    font-size-adjust:none;
+    font-style:normal;
+    font-variant:normal;
+    font-weight:normal;
+    line-height:13px;
+}
+.p-thumb-wrap span{
+  
+       display: block;
+       overflow: hidden;
+       text-align: center;
+    height: 40px;
+    width: 80px;
+}
+.p-thumb-view .x-view-selected {
+    background: #316AC5 !important;
+}
+
+.p-reply-to-link 
+{
+    color :#0c0;
+    font-style: normal;
+    font-weight: bold;
+    cursor:pointer;
+
+}
+
+.p-doc-unread td
+{
+    font-weight: bold;
+   }
+   
+span.ptcv-selectlang
+{
+   text-decoration: underline; 
+   color : #00f;
+   cursor:pointer;
+}
+   
+/** -------------------- ACTION BOXES ----------------- */
+.x-action-box
+{
+     font-family:arial,tahoma,helvetica,sans-serif;
+    font-size:11px;
+    font-size-adjust:none;
+    font-style:normal;
+    font-variant:normal;
+    font-weight:normal;
+    line-height:13px;
+}
+.x-action-box-header {
+    -moz-background-clip:border;
+    -moz-background-inline-policy:continuous;
+    -moz-background-origin:padding;
+    background:#E3E3E3 none repeat scroll 0 0;
+    border-left: 1px solid #ccc;
+    border-top: 1px solid #ccc;
+    border-bottom: 1px solid #ccc;
+    color:#333;
+}
+.x-action-box-small-header {
+    padding:8px 12px 4px;
+}
+.x-action-box-properties-header {
+    font-size:120%;
+    font-weight:bold;
+}
+.x-action-box-top-right {
+    background-image:url(../action/shcornertop.png);
+    background-repeat:no-repeat;
+  /*  height:12px; */
+    min-width:12px;
+    width:1%;
+}
+
+.x-action-box-right {
+    background-image:url(../action/shr.png);
+    background-repeat:repeat-y;
+}
+.x-action-box-body {
+    -moz-background-clip:border;
+    -moz-background-inline-policy:continuous;
+    -moz-background-origin:padding;
+    background:white none repeat scroll 0 0;
+    padding:10px;
+     border-left: 1px solid #ccc;
+}
+.x-action-box-ico-edit {
+    -moz-background-clip:border !important;
+    -moz-background-inline-policy:continuous !important;
+    -moz-background-origin:padding !important;
+    /* background:transparent url(../../images/16x16/all_16_16_vertical.png) no-repeat scroll 0 -378px !important; */
+}
+.x-action-box-action {
+    background-position:0 2px;
+    background-repeat:no-repeat;
+    padding:3px 0 2px 22px;
+    cursor:pointer;
+    color: #33c;
+    text-decoration: underline;
+    clear: both;
+    float: left;
+    line-height: 15px;
+}
+.x-action-box-bottom-left {
+    background-image:url(../action/shcornerbottom.png);
+    background-repeat:no-repeat;
+    height:12px;
+  /*   min-width:12px; */
+    width:1%;
+}
+.x-action-box-bottom {
+    background-image:url(../action/shb.png);
+    background-repeat:repeat-x;
+}
+.x-action-box-bottom-right {
+    background-image:url(../action/shcorner.png);
+    background-repeat:no-repeat;
+    height:12px;
+    min-width:12px;
+    width:1%;
+}
+.x-action-box-hr {
+    border-bottom:1px solid #DDDDDD;
+    margin-bottom:2px;
+    padding-bottom:2px;
+    padding-top:4px;
+    clear:both;
+}
+/*** -------------- boxes with themes ----- */
+.x-action-box-yellow .x-action-box-header
+{
+    background:#F6D64E none repeat scroll 0 0;
+    border-color:#C9A30A;
+    color:#655205;
+}
+.x-action-box-yellow .x-action-box-body
+{
+    
+   background:#FFF2BF none repeat scroll 0 0;
+    color:#655205;
+}
\ No newline at end of file
diff --git a/templates/master.html b/templates/master.html
new file mode 100644 (file)
index 0000000..7abda7e
--- /dev/null
@@ -0,0 +1,147 @@
+<!DOCTYPE html 
+      PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" 
+      xmlns:html="http://www.w3.org/1999/xhtml" 
+      xmlns:svg="http://www.w3.org/2000/svg"
+      xmlns:xlink="http://www.w3.org/1999/xlink"> 
+    <head>
+        <title>{appName}</title>
+        <link rel="shortcut icon" href="./Pman.ico" type="image/vnd.microsoft.icon"/>
+        
+        <link rel="stylesheet" type="text/css" href="/roojs1/cssX/roojs-all.css" />
+        
+        {outputCSSIncludes()}
+        
+                    
+   
+    <style>
+     #loading-logo-bottom,
+     #loading-logo-center,
+     #loading-logo-tile,
+     #loading-logo-tile-top
+     {
+        width:100%;
+        height:100%;
+        position:absolute;
+       
+        left:0;
+        top:0;
+        background-position:50% 50%;
+    }
+    
+    /* background-tile.jpg */
+    #loading-logo-tile {
+         z-index:1000;
+    }
+    
+    /* background.jpg */
+    #loading-logo-center
+    {
+        background-position:50% 0;
+        background-repeat:no-repeat; 
+        z-index:1001;
+    }
+    /* background-tile-top.jpg */
+    #loading-logo-tile-top
+    {
+        background-position:50% 0;
+        z-index:1002;
+        background-repeat:repeat-x; 
+        
+    }
+    /* background_bottom_logo.gif */
+    #loading-logo-bottom
+    {
+        background-position:50% 100%;
+        background-repeat:no-repeat; 
+        z-index:1003;
+    }
+    </style>
+     </head>
+    <body class="ytheme-gray">  
+         <!--background:#F8ECB2;-->   
+        <div flexy:if="hasBg(#background-tile.jpg#)" 
+            id="loading-logo-tile"
+            style="background-image:url({rootURL}/Pman/{appNameShort}/templates/images/background-tile.jpg);"></div>
+        
+        <div flexy:if="hasBg(#background-tile-top.jpg#)"  
+            id="loading-logo-tile-top"
+            style="background-image:url({rootURL}/Pman/{appNameShort}/templates/images/background-tile-top.jpg);"></div>
+        
+        <div flexy:if="hasBg(#background.jpg#)" 
+            id="loading-logo-center"
+            style="background-image:url({rootURL}/Pman/{appNameShort}/templates/images/background.jpg);"></div>
+        
+        <div flexy:if="hasBg(#background_bottom_logo.gif#)" 
+            id="loading-logo-bottom"
+            style="background-image:url({rootURL}/Pman/{appNameShort}/templates/images/background_bottom_logo.gif);"></div>
+        
+        
+        <div id="loading-mask"
+            style="width:1;height:1;position:absolute;z-index:1000;left:0;top:0;">&#160;</div>
+        <div id="loading">
+            <div class="loading-indicator" id="loading-text">&#160;Loading...(This may take a few seconds)</div>
+        </div>
+{if:isDev}                  
+        <script type="text/javascript" src="/roojs1/roojs-debug.js"></script>  
+         
+{else:}                  
+        <script type="text/javascript" src="/roojs1/roojs-all.js"></script>
+                 
+{end:}                  
+        <flexy:toJavascript 
+            baseURL="baseURL" 
+            rootURL="rootURL" 
+            isDev="isDev"
+            serverName="serverName" 
+            appLang="lang"
+            appName="appName"
+            appNameShort="appNameShort"
+            appOwnerCompanyId="company.id"
+             
+            AppLinkError="linkFail"
+            AppTrackOnLoad="onloadTrack"
+            
+            showNewPass="showNewPass"
+            allowSignup="allowSignup"
+            
+            logoPrefix="logoPrefix"
+            
+            AppModules="appModules"
+            AppVersion="appVersion"
+        >
+        
+        <script type="text/javascript">
+            Ext=Roo; // bc
+            Roo.BLANK_IMAGE_URL =  "/roojs1/images/gray/s.gif";
+            Roo.rootURL = '/roojs1/';
+        </script>
+        
+        {outputJavascriptIncludes()}
+             
+        <!-- used by App.php in Builder - to enable loading of code/applicaiton on the fly -->
+        {foreach:builderJs,js}
+            <script type="text/javascript" src="{baseURL}/Builder/Code/{js}.js"></script>    
+        {end:} 
+                
+                
+        <div id="title" class="x-layout-inactive-content logoblock">
+            <img id="headerInformation-company-logo" 
+                src="{rootURL}/Pman/{appNameShort}/templates/images/logo_small.gif" height="25"/>
+            <div id="headerInformation">Some other details</div>
+            <img id="headerInformation-applogo" 
+                src="{rootURL}/Pman/{appNameShort}/templates/images/logo_small.gif" height="25"/>
+            
+        </div>
+         
+          
+           
+        <div id="mainlist" class="x-layout-inactive-content">
+            <p>main list</p>
+                
+        </div>
+          
+    </body>
+</html>
+        
\ No newline at end of file
diff --git a/widgets/ActionBox.js b/widgets/ActionBox.js
new file mode 100644 (file)
index 0000000..b426b3e
--- /dev/null
@@ -0,0 +1,214 @@
+//<script type="text/javascript">
+
+
+Roo.box = Roo.box || {};
+
+Roo.box.Action = function(cfg) {
+    Roo.apply(this, cfg);
+    this.midwidth = this.width - 24; 
+};
+
+Roo.box.Action.prototype = {
+    
+    width : 240,
+    items : [],
+    midwidth : 218,
+    title : '',
+    zitems: '',
+    cls : '',
+    render : function(el)
+    {
+        
+        this.initTemplate();
+        this.id = Roo.id();
+        this.midwidth = this.width - 22;
+        this.subwidth = this.midwidth-18;
+        Roo.box.Action.tmpl.append(el, this);
+        Roo.each(this.items, function(o, i) {
+            o.initHandler();
+        });
+        this.el = Roo.get(this.id);
+        this.el.setVisibilityMode(Roo.Element.DISPLAY);
+    },
+    initTemplate : function()
+    {
+        if (Roo.box.Action.tmpl) {
+            return;
+        }
+        
+        
+        Roo.box.Action.tmpl = new Roo.Template(
+                    
+            '<table id="{id}" style="width: {width}px; border-collapse: collapse;" class="x-action-box {cls}">',
+                '<col width="12"/><col width="{midwidth}"/><col width="12"/>',
+                '<tbody>',
+                    '<tr>',
+                        '<td rowspan="2" colspan="2" class="x-action-box-header x-action-box-small-header">',
+                            '<div class="x-action-box-properties-header">{title}</div>',
+                        '</td>',
+                        '<td class="x-action-box-top-right"/>',
+                    '</tr>',
+                '<tr>',
+                    '<td rowspan="2" class="x-action-box-right"/>',
+                '</tr>',
+                '<tr>',
+                    '<td colspan="2" class="x-action-box-body">',
+                        '<div style="width: {subwidth}px">{zitems:this.renderItems}</div>',
+                    '</td>',
+                '</tr>',
+                '<tr>',
+                    '<td style="width: 12px;" class="x-action-box-bottom-left"></td>',
+                    '<td style="width: {midwidth}px;" class="x-action-box-bottom"/>',
+                    '<td style="width: 12px;" class="x-action-box-bottom-right"></td>',
+                '</tr>',
+            '</tbody>',
+            '</table>'
+        );
+        Roo.box.Action.tmpl.renderItems = function (v, allv) {
+            return Roo.box.Action.prototype.renderItems(v,allv); // ensure scope of this.. 
+        };
+        Roo.box.Action.tmpl.compile();
+        
+    },
+    renderItems : function (items, obj) {
+        var ret = '';
+        //console.log(obj);
+        Roo.each(obj.items, function(o, i) {
+            obj.items[i] =  Roo.factory(o, Roo.box);
+            
+            ret += obj.items[i].render(obj);
+        });
+        //console.log(ret);
+        return ret;
+    },
+    get : function(n) {
+        var ret = false;
+        Roo.each(this.items, function(o) {
+            if (o.name == n) {
+                ret = o;
+                return false;
+            }
+        });
+        return ret;
+    },
+    hide: function()
+    {
+        this.el.hide();
+    },
+    show: function()
+    {
+        this.el.show();
+    }
+    
+     
+    
+};
+
+Roo.box.Link = function(cfg) {
+    Roo.apply(this, cfg);
+};
+
+Roo.box.Link.prototype = {
+    name : false,
+    handler : false,
+    id : false,
+    title : 'empty',
+    el: false,
+    icon : false,
+    render: function(obj) {
+        this.id = Roo.id();
+        return Roo.DomHelper.markup({
+            tag: 'div',
+            id : this.id,
+            cls : 'x-action-box-action x-action-ico-edit',
+            style : 'display: block;' + ( this.icon ? 'background-image: url(' + this.icon + ');' : ''),
+            html : String.format('{0}', this.title)
+        });
+          
+    },
+    initHandler: function() 
+    {
+        if (this.id) {
+            this.el = Roo.get(this.id);
+            this.el.setVisibilityMode(Roo.Element.DISPLAY);
+        }
+        if (this.el && this.handler) {
+            Roo.get(this.id).on('click', this.handler);
+        }
+         
+    },
+    
+    hide: function() {
+        if (this.el) {
+            this.el.hide();
+        }
+    },
+    show: function() {
+        if (this.el) {
+            this.el.show();
+        }
+    },
+    setValue: function(v) {
+        if (!this.edid) {
+            return;
+        }
+        this.value = v;
+        Roo.get(this.edid).dom.innerHTML = v; // unfiltered..
+    }
+    
+    
+};
+Roo.box.Hr = function(cfg) {
+    Roo.apply(this, cfg);
+    
+};
+
+Roo.extend(Roo.box.Hr, Roo.box.Link , {
+    handler : false,
+    id : false,
+    render: function(obj) {
+        return  '<div  class="x-action-box-hr"></div>'
+    }
+});
+
+Roo.box.KeyValShort = function(cfg) {
+    Roo.apply(this, cfg);
+    
+};
+
+Roo.extend(Roo.box.KeyValShort, Roo.box.Link , {
+    handler : false,
+    id : false,
+    key: 'key',
+    value : 'value',
+    render: function(obj) {
+        this.id = Roo.id();
+        this.edid = Roo.id();
+        return  String.format('<div id="{3}" class="x-action-prop-col-div">' + 
+                '<span style="font-weight: bolder;">{0}: </span><span id="{2}">{1}</span></div>', 
+            this.key, this.value, this.edid,this.id);
+    }
+}); 
+
+
+
+
+Roo.box.KeyValLong = function(cfg) {
+    Roo.apply(this, cfg);
+    
+};
+
+Roo.extend(Roo.box.KeyValLong, Roo.box.Link , {
+    handler : false,
+    id : false,
+    key: 'key',
+    value : 'value',
+    render: function(obj) {
+        this.id = Roo.id();
+        this.edid = Roo.id();
+        return  String.format('<span id="{3}"><span style="color: rgb(51, 51, 51); font-weight: bolder;">{0}</span><br/>'+
+            '<div id="{2}" style="padding-left: 10px; overflow:hidden;">{1} </div></span>', 
+            this.key, this.value, this.edid,this.id).replace(/\n/g, '<BR/>\n');
+    }
+});
+
diff --git a/widgets/ColorField.js b/widgets/ColorField.js
new file mode 100644 (file)
index 0000000..94f440f
--- /dev/null
@@ -0,0 +1,61 @@
+//<script type="text/javascript">
+
+
+/**
+* Color field
+*/
+
+
+Roo.form.ColorField = function(config){
+    Roo.form.ColorField.superclass.constructor.call(this, config);
+   
+};
+Roo.extend(Roo.form.ColorField, Roo.form.TriggerField , {
+     
+    defaultAutoCreate : {tag: 'input', type: 'text', size: '6',   autocomplete: 'off'},
+    validateValue : function(value){
+        this.setBgColor(value);
+        return true;
+    },
+    menuListeners : {
+        select: function(m, d){
+            this.setValue(d);
+        },
+        show : function(){ 
+            this.onFocus();
+        },
+        hide : function(){
+            this.focus.defer(10, this);
+            var ml = this.menuListeners;
+            this.menu.un('select', ml.select, this);
+            this.menu.un('show', ml.show, this);
+            this.menu.un('hide', ml.hide, this);
+        }
+    },
+    onTriggerClick : function(){
+        if(this.disabled){
+            return;
+        }
+        if(this.menu == null){
+            this.menu = new Roo.menu.ColorMenu();
+        }
+         
+        this.menu.on(Roo.apply({}, this.menuListeners, {
+            scope:this
+        }));
+        //this.menu.picker.setValue(this.getValue() || new Date());
+        this.menu.show(this.el, 'tl-bl?');
+    }, 
+    setValue: function(d) {
+        d = (typeof(d) != 'undefined') && d.length ? d : 'FFFFFF';
+        
+        Roo.form.ColorField.superclass.setValue.call(this, d);
+        this.setBgColor(d);
+    },
+    
+    setBgColor : function(d) {
+        var d = (typeof(d) != 'undefined') && d.length ? d : 'FFFFFF';
+        this.el.dom.style.background ='#' + d;
+    }
+});
\ No newline at end of file
diff --git a/widgets/ComboBoxAdder.js b/widgets/ComboBoxAdder.js
new file mode 100644 (file)
index 0000000..61a7522
--- /dev/null
@@ -0,0 +1,101 @@
+
+//<script type="text/javascript">
+
+
+
+Ext.form.ComboBoxAdder = function(config){
+    
+    Ext.form.ComboBoxAdder.superclass.constructor.call(this, config);
+    this.on('select', function(cb, rec, ix) {
+        cb.lastData = rec.data;
+    });
+    this.addEvents({
+        'adderclick' : true
+    });
+}
+Ext.extend(Ext.form.ComboBoxAdder, Ext.form.ComboBox, { 
+    lastData : false,
+    //onAddClick: function() { },
+    
+    onRender : function(ct, position) 
+    {
+        Ext.form.ComboBoxAdder.superclass.onRender.call(this, ct, position); 
+        this.adder = this.wrap.createChild(
+            {tag: 'img', src: Ext.BLANK_IMAGE_URL, cls: 'x-form-adder' });  
+        var _t = this;
+        this.adder.on('click', function(e) {
+            _t.fireEvent('adderclick', this, e);
+        }, _t);
+        //this.adder.on('click', this.onAddClick, _t);
+    }
+    
+});
+
+
+
+Ext.form.TextFieldAdder = function(config){
+    
+    Ext.form.TextFieldAdder.superclass.constructor.call(this, config);
+    this.on('select', function(cb, rec, ix) {
+        cb.lastData = rec.data;
+    });
+    this.addEvents({
+        'adderclick' : true
+    });
+}
+Ext.extend(Ext.form.TextFieldAdder, Ext.form.TextField, { 
+    lastData : false,
+    //onAddClick: function() { },
+    
+    onRender : function(ct, position) 
+    {
+        Ext.form.TextFieldAdder.superclass.onRender.call(this, ct, position); 
+         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
+        this.adder = this.wrap.createChild(
+            {tag: 'img', src: Ext.BLANK_IMAGE_URL, cls: 'x-form-textfield-adder'});  
+        var _t = this;
+        this.adder.on('click', function(e) {
+            _t.fireEvent('adderclick', this, e);
+        }, _t);
+    }
+    
+});
+
+
+Ext.form.TextFieldAdderMinus = function(config){
+    
+    Ext.form.TextFieldAdder.superclass.constructor.call(this, config);
+    this.on('select', function(cb, rec, ix) {
+        cb.lastData = rec.data;
+    });
+    this.addEvents({
+        'adderclick' : true,
+        'minusclick' : true
+    });
+}
+Ext.extend(Ext.form.TextFieldAdderMinus, Ext.form.TextField, { 
+    lastData : false,
+    //onAddClick: function() { },
+    
+    onRender : function(ct, position) 
+    {
+        Ext.form.TextFieldAdder.superclass.onRender.call(this, ct, position); 
+         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
+        this.adder = this.wrap.createChild(
+            {tag: 'img', src: Ext.BLANK_IMAGE_URL, width: 16, cls: 'x-form-textfield-adder'});  
+        this.minus = this.wrap.createChild(
+            {tag: 'img', src: Ext.BLANK_IMAGE_URL, width: 16, cls: 'x-form-textfield-minus'});  
+        var _t = this;
+        this.adder.on('click', function(e) {
+            _t.fireEvent('adderclick', this, e);
+        }, _t);
+        this.minus.on('click', function(e) {
+            _t.fireEvent('minusclick', this, e);
+        }, _t);
+    }
+    
+});
+
diff --git a/widgets/ComboBoxLister.js b/widgets/ComboBoxLister.js
new file mode 100644 (file)
index 0000000..e58e3b8
--- /dev/null
@@ -0,0 +1,195 @@
+//<script type="text/javascript">
+/**
+ * 
+ * A facebook style adder... for lists of email / people etc...
+ * 
+ * 
+ * 
+ */
+
+
+Ext.form.ComboBoxLister = function(config){
+    
+    Ext.form.ComboBoxLister.superclass.constructor.call(this, config);
+    this.items = new Roo.util.MixedCollection(false);
+    this.on('select', function(cb, rec, ix) {
+        this.addItem(rec.data);
+        this.setValue('');
+        this.el.dom.value = '';
+        //cb.lastData = rec.data;
+        // add to list
+        
+    });
+    
+}
+Ext.extend(Ext.form.ComboBoxLister, Ext.form.ComboBox, { 
+    lastData : false,
+    items  : false,
+    nameField : 'name',
+    tipField : 'email',
+    idField : 'id',
+    renderer : false,
+    hiddenName : false, // set this if you want a , sperated list of values in it for form posting..
+    hiddenListName : false,
+    hiddenEl : false,
+    boxWidth : 200, // use to set the box around the entry..
+    allowBlank: true,
+    disableClear: true,
+    //validateValue : function() { return true; }, // all values are ok!
+    //onAddClick: function() { },
+    
+    onRender : function(ct, position) 
+    {
+         
+        Ext.form.ComboBoxLister.superclass.onRender.call(this, ct, position); 
+        this.wrap.addClass('p-cblist-grp');
+        var cbwrap = this.wrap.createChild(
+            {tag: 'div', cls: 'p-cblist-cb'},
+            this.el.dom
+        );  
+        if (this.hiddenListName) {
+             
+            this.hiddenEl = this.wrap.createChild({
+                tag: 'input',  type:'hidden' , name: this.hiddenListName, value : ''
+            });
+         //   this.el.dom.removeAttribute("name");
+        }
+        
+        this.outerWrap = this.wrap;
+        this.wrap = cbwrap;
+        this.outerWrap.setWidth(this.boxWidth);
+        this.outerWrap.dom.removeChild(this.el.dom);
+        this.wrap.dom.appendChild(this.el.dom);
+        this.outerWrap.dom.removeChild(this.trigger.dom);
+        this.wrap.dom.appendChild(this.trigger.dom);
+        
+        this.trigger.setStyle('position', 'relative');
+        this.trigger.setStyle('vertical-align', 'top');
+        if (this.adder) {
+            
+        
+            this.adder = this.outerWrap.createChild(
+                {tag: 'img', src: Ext.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});  
+            var _t = this;
+            this.adder.on('click', function(e) {
+                _t.fireEvent('adderclick', this, e);
+            }, _t);
+        }
+        //var _t = this;
+        //this.adder.on('click', this.onAddClick, _t);
+        
+    },
+    addItem: function(rec)
+    {
+        if (this.items.indexOfKey(rec[this.idField]) > -1) {
+            //console.log("GOT " + rec.data.id);
+            return;
+        }
+        
+        var x = new Ext.form.ComboBoxLister.Item({
+            //id : rec[this.idField],
+            data : rec,
+            nameField : this.nameField,
+            tipField : this.tipField,
+            cb : this
+        });
+        // use the 
+        this.items.add(rec[this.idField],x);
+        // add it before the element..
+        this.updateHiddenEl();
+        x.render(this.outerWrap, this.wrap.dom);
+        // add the image handler..
+    },
+    
+    updateHiddenEl : function()
+    {
+        this.validate();
+        if (!this.hiddenEl) {
+            return;
+        }
+        var ar = [];
+        var idField = this.idField;
+        this.items.each(function(f) {
+            ar.push(f.data[idField]);
+           
+        });
+        this.hiddenEl.dom.value = ar.join(',');
+        this.validate();
+    },
+    
+    reset : function()
+    {
+        Roo.form.ComboBoxLister.superclass.reset.call(this); 
+        this.items.each(function(f) {
+           f.remove(); 
+        });
+        if (this.hiddenEl) {
+            this.hiddenEl.dom.value = '';
+        }
+        
+    },
+    getValue: function()
+    {
+        return this.hiddenEl ? this.hiddenEl.dom.value : '';
+    },
+    setValue: function(v) // not a valid action - must use addItems..
+    {
+        if (typeof(v) != 'object') {
+            return;
+        }
+        var _this = this;
+        Roo.each(v, function(l) {
+                _this.addItem(l);
+        });
+        
+    },
+    validateValue : function(value){
+        return Roo.form.ComboBoxLister.superclass.validateValue.call(this, this.getValue());
+        
+    }
+    
+});
+
+Ext.form.ComboBoxLister.Item = function(config) {
+    config.id = Roo.id();
+    Roo.form.ComboBoxLister.Item.superclass.constructor.call(this, config);
+}
+Roo.extend(Roo.form.ComboBoxLister.Item, Roo.BoxComponent, {
+    data : {},
+    cb: false,
+    defaultAutoCreate : {tag: 'div', cls: 'p-cblist-item', cn : [ 
+            { tag: 'div' },
+            { tag: 'img', width:16, height : 16, src : Roo.BLANK_IMAGE_URL , align: 'center' }
+        ]
+        
+    },
+    
+    onRender : function(ct, position){
+        Roo.form.Field.superclass.onRender.call(this, ct, position);
+        if(!this.el){
+            var cfg = this.getAutoCreate();
+            this.el = ct.createChild(cfg, position);
+        }
+        this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
+        
+        this.el.child('div').dom.innerHTML = this.cb.renderer ? 
+            this.cb.renderer(this.data) : String.format('{0}',this.data[this.nameField]);
+        this.el.child('div').dom.setAttribute('qtip', String.format('{0}',this.data[this.tipField]));
+        
+        this.el.child('img').on('click', this.remove, this);
+        
+    },
+   
+    remove : function()
+    {
+        
+        this.cb.items.remove(this);
+        this.el.child('img').un('click', this.remove, this);
+        this.el.remove();
+        this.cb.updateHiddenEl();
+    }
+    
+    
+});
\ No newline at end of file
diff --git a/widgets/ContentPanel2.js b/widgets/ContentPanel2.js
new file mode 100644 (file)
index 0000000..c9fa40e
--- /dev/null
@@ -0,0 +1,34 @@
+//<script type="text/javascript">
+
+
+// I'm not sure if this is the best way to do this..
+
+
+Roo.ContentPanel2 = function(el, config, content){
+     Roo.ContentPanel2.superclass.constructor.call(this,el, config, content);
+     
+}
+Roo.extend(Roo.ContentPanel2, Roo.ContentPanel, {
+    adjustForComponents : function(width, height){
+        if(this.resizeEl != this.el){
+            width -= this.el.getFrameWidth('lr');
+            height -= this.el.getFrameWidth('tb');
+        }
+        if(this.toolbar){
+            var te = this.toolbar.getEl();
+            height -= te.getHeight();
+            te.setWidth(width);
+        }
+        if(this.toolbar2){
+            var te = this.toolbar2.getEl();
+            height -= te.getHeight();
+            te.setWidth(width);
+        }
+        if(this.adjustments){
+            width += this.adjustments[0];
+            height += this.adjustments[1];
+        }
+        return {'width': width, 'height': height};
+    }
+});
+        
\ No newline at end of file
diff --git a/widgets/DisplayImage.js b/widgets/DisplayImage.js
new file mode 100644 (file)
index 0000000..f896cad
--- /dev/null
@@ -0,0 +1,143 @@
+//<script type="text/javascript">
+/**
+ * @class Ext.form.Checkbox
+ * @extends Ext.form.Field
+ * Single checkbox field.  Can be used as a direct replacement for traditional checkbox fields.
+ * @constructor
+ * Creates a new Checkbox
+ * @param {Object} config Configuration options
+ */
+Ext.form.DisplayImage = function(config){
+    Ext.form.DisplayImage.superclass.constructor.call(this, config);
+     
+};
+
+Ext.extend(Ext.form.DisplayImage, Ext.form.Field,  {
+    /**
+     * @cfg {Number} width  - mostly ignored
+     */
+    width : 100,
+    /**
+     * @cfg {Number} height - used to restrict height of image..
+     */
+    width : 50,
+     /**
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     */
+    
+    /**
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     */
+    focusClass : undefined,
+    /**
+     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
+     */
+    fieldClass: 'x-form-field',
+    /**
+     * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
+     */
+    checked: false,
+    /**
+     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "checkbox", autocomplete: "off"})
+     */
+   // defaultAutoCreate : { tag: 'div' },
+     defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
+    /**
+     * @cfg {String} addTitle Text to include for adding a title.
+     */
+     addTitle : false,
+    /**
+     * @cfg {Function} renderer Method to return raw HTML to render for the image..
+     */ 
+     
+    //
+    onResize : function(){
+        Ext.form.Field.superclass.onResize.apply(this, arguments);
+        
+    },
+
+    initEvents : function(){
+        // Ext.form.Checkbox.superclass.initEvents.call(this);
+        // has no events...
+       
+    },
+
+
+    getResizeEl : function(){
+        return this.wrap;
+    },
+
+    getPositionEl : function(){
+        return this.wrap;
+    },
+
+    // private
+    onRender : function(ct, position){
+        
+        this.style = this.style || '';
+        var style = this.style;
+        delete this.style;
+        
+        Ext.form.DisplayImage.superclass.onRender.call(this, ct, position);
+        this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
+        this.viewEl = this.wrap.createChild({ tag: 'table',  html : '<tr><td align="center"></td></tr>' });
+        if (style) {
+            this.viewEl.applyStyles(style);
+        }
+        if (this.width) {
+            this.viewEl.setWidth(this.width);
+        }
+        if (this.height) {
+            this.viewEl.setHeight(this.height);
+        }
+        //if(this.inputValue !== undefined){
+        //this.setValue(this.value);
+        
+        
+        
+    },
+
+    // private
+    initValue : Ext.emptyFn,
+
+    /**
+     * Returns the checked state of the checkbox.
+     * @return {Boolean} True if checked, else false
+     */
+    
+    /**
+     * Sets the value of the item. 
+     * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
+     */
+    setValue : function(v){
+        this.value = v;
+        
+        if (!this.el) {
+            return;
+        }
+        var html = this.renderer ? 
+            this.renderer(v)
+            : String.format('<img src="{0}" height="{1}">', Roo.BLANK_IMAGE_URL, this.height);
+       
+        var id = false;
+        if (this.addTitle) {
+            id = Roo.id();
+            html += '<p id="' + id + '" class="x-action-box-action x-action-ico-edit x-action-box" ' +
+            ' style="display: block;' + ( this.icon ? 'background-image: url(' + this.icon + ');' : '') + '"' +
+            '>' + this.addTitle + '</p>';
+        }
+        // unlink old handler???
+        // width is flexible...
+        this.viewEl.child('td').dom.innerHTML = html;
+        if (id && this.handler) {
+            Roo.get(id).on('click', this.handler, this);
+        }
+        
+        Roo.form.DisplayImage.superclass.setValue.call(this, v);
+    }
+    
+     
+    
+    
+});
\ No newline at end of file
diff --git a/widgets/DisplayText.js b/widgets/DisplayText.js
new file mode 100644 (file)
index 0000000..930c6ea
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Ext.form.DisplayText
+ * @extends Ext.form.Field
+ * Display text field 
+ * @constructor
+ * Creates a new Display text fiedl
+ * @param {Object} config Configuration options
+ */
+Ext.form.DisplayText = function(config){
+    Ext.form.DisplayText.superclass.constructor.call(this, config);
+    
+};
+
+Ext.extend(Ext.form.DisplayText, Ext.form.Field,  {
+     /**
+     * @cfg {Number} width  - mostly ignored
+     */
+    width : 100,
+    /**
+     * @cfg {Number} height - used to restrict height of image..
+     */
+    width : 50,
+    /**
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     */
+    focusClass : undefined,
+    /**
+     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
+     */
+    fieldClass: 'x-form-field',
+    
+    /**
+     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "checkbox", autocomplete: "off"})
+     */
+     
+    defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
+
+    /**
+     * @cfg {String} inputValue The value that should go into the generated input element's value attribute
+     */
+    //
+    onResize : function(){
+        Ext.form.Field.superclass.onResize.apply(this, arguments);
+        
+    },
+
+    initEvents : function(){
+        // Ext.form.Checkbox.superclass.initEvents.call(this);
+        // has no events...
+       
+    },
+
+
+    getResizeEl : function(){
+        return this.wrap;
+    },
+
+    getPositionEl : function(){
+        return this.wrap;
+    },
+
+    // private
+    onRender : function(ct, position){
+        Ext.form.DisplayText.superclass.onRender.call(this, ct, position);
+        //if(this.inputValue !== undefined){
+        
+        this.style = this.style || '';
+        var style = this.style;
+        delete this.style;
+        
+        Ext.form.DisplayImage.superclass.onRender.call(this, ct, position);
+        this.wrap = this.el.wrap({cls: 'x-menu-check-item'});
+        this.viewEl = this.wrap.createChild({ tag: 'div'});
+        
+        if (style) {
+            this.viewEl.applyStyles(style);
+        }
+        this.viewEl.setStyle('padding', '2px');
+        if (this.width) {
+            this.viewEl.setWidth(this.width);
+        }
+        if (this.height) {
+            this.viewEl.setHeight(this.height);
+        }
+        this.setValue(this.value);
+        
+
+        
+        
+    },
+
+    // private
+    initValue : Ext.emptyFn,
+
+  
+
+       // private
+    onClick : function(){
+        
+    },
+
+    /**
+     * Sets the checked state of the checkbox.
+     * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
+     */
+    setValue : function(v){
+        this.value = v;
+        var html = this.renderer ?  this.renderer(v) : String.format('{0}', v);
+
+        this.viewEl.dom.innerHTML = html;
+        Roo.form.DisplayText.superclass.setValue.call(this, v);
+
+    }
+});
\ No newline at end of file
diff --git a/widgets/Document.js b/widgets/Document.js
new file mode 100644 (file)
index 0000000..1430bf1
--- /dev/null
@@ -0,0 +1,35 @@
+//<script type="text/javascript">
+
+/**
+ * 
+ *  Generic Page handler - implement this to start your app..
+ * 
+ * 
+ * 
+ * eg.
+ *  MyProject = new Roo.Document({
+        events : {
+            'load' : true // your events..
+        },
+        listeners : {
+            'ready' : function() {
+                // fired on Ext.onReady()
+            }
+        }
+ * 
+ */
+Roo.Document = function(cfg) {
+     
+    this.addEvents({ 
+        'ready' : true
+    });
+    Roo.util.Observable.call(this,cfg);
+    var _this = this;
+    Roo.onReady(function() {
+        _this.fireEvent('ready');
+    },null,false);
+    
+}
+Roo.extend(Roo.Document, Roo.util.Observable, {
+    
+});
\ No newline at end of file
diff --git a/widgets/Ext.bugs.js b/widgets/Ext.bugs.js
new file mode 100644 (file)
index 0000000..57a2779
--- /dev/null
@@ -0,0 +1,244 @@
+// <script type="text/javascript">
+ /* this knocks about 3000ms off the startup - total is 13000 originally. */
+  
+ (function(){
+       var propCache = {},
+               camelRe = /(-[a-z])/gi,
+               classReCache = {},
+               view = document.defaultView,
+               propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat',
+               opacityRe = /alpha\(opacity=(.*)\)/i;
+    Ext.propCache = propCache; 
+    
+       function camelFn (a) {
+               return a.charAt(1).toUpperCase();
+       };
+       function chkCache(prop){
+               return propCache[prop] ||
+                       (propCache[prop] = prop == 'float' ? 
+                propFloat : prop.replace(camelRe, camelFn));
+       };
+       Ext.override(Ext.Element, {
+               getStyle : function(){
+                       return view && view.getComputedStyle ?
+                               function(prop){
+                    // ie!!!.
+                                       var el = this.dom, v, cs;
+                                       if(el == document) return null;
+                                       prop = chkCache(prop);
+                    
+                                       return (v = el.style[prop]) ? v :
+                                                  (cs = view.getComputedStyle(el, '')) ?
+                            cs[prop] : null;
+                               } :
+                               function(prop){
+                                       var el = this.dom, m, cs;
+                                       if(el == document) return null;
+                                       if (prop == 'opacity') {
+                                               if (el.style.filter.match) {
+                                                       if(m = el.style.filter.match(opacityRe)){
+                                                               var fv = parseFloat(m[1]);
+                                                               if(!isNaN(fv)){
+                                                                       return fv ? fv / 100 : 0;
+                                                               }
+                                                       }
+                                               }
+                                               return 1;
+                                       }
+                                       prop = chkCache(prop);
+                                       return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
+                               };
+               }(),
+               setStyle : function(prop, value){
+                       var tmp,
+                               style,
+                               camel;
+                       if (typeof(prop) != 'object') {
+                               tmp = {};
+                               tmp[prop] = value;
+                               prop = tmp;
+                       }
+                       for (style in prop) {
+                               value = prop[style];
+                               style == 'opacity' ?
+                                       this.setOpacity(value) :
+                                       this.dom.style[chkCache(style)] = value;
+                       }
+                       return this;
+               }
+       })
+})();
+
+
+// added to roo...
+Ext.override(Ext.dd.StatusProxy, {
+       update : function(html){
+               if(typeof html == 'string'){
+                       this.ghost.update(html);
+               }else{
+                       this.ghost.update('');
+                       html.style.margin = '0';
+                       this.ghost.dom.appendChild(html);
+               }
+               var el = this.ghost.dom.firstChild;
+               if(el){
+                       Ext.fly(el).setStyle('float', 'none');
+               }
+       }
+});
+
+// added to roo....
+Ext.override(Ext.grid.ColumnModel, {
+    
+    
+    getIndexByDataIndex : function(x){ // fixme - find refs and remove them!
+        return this.findColumnIndex(x);
+    }
+});
+Ext.override(Ext.grid.GridView, { 
+  
+    updateColumns : function(){ // this was added before I worked out the fix to the cols.
+        this.grid.stopEditing();
+        var cm = this.grid.colModel, colIds = this.getColumnIds();
+        //var totalWidth = cm.getTotalWidth();
+        var pos = 0;
+        var ci = '';
+        var w = 0;
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
+            //if(cm.isHidden(i)) continue;
+            w = cm.getColumnWidth(i);
+            ci = Roo.isSafari ? colIds[i].toLowerCase() : colIds[i];
+          //  console.log('UPDATE COLS: " +this.colSelector+colIds[i] + '=>' + (w - this.borderWidth)+ "px");
+            this.css.updateRule(this.colSelector+ci, 'width', (w - this.borderWidth) + 'px');
+            
+            this.css.updateRule(this.hdSelector+ci, 'width', (w - this.borderWidth) + 'px');
+        }
+        this.updateSplitters();
+       // this.forceLayout.defer(100,this);
+    } 
+
+
+
+});
+ /*
+String.format =  function(format) {
+    var args = Array.prototype.slice.call(arguments, 1);
+    return format.replace(/\{(\d+)\}/g, function(m, i) {
+       
+        var e = document.createTextNode( args[i]  );
+        var ew = document.createElement('a');
+        ew.appendChild(e);
+        return ew.innerHTML;
+    });
+};
+*/
+Ext.grid.ColumnModel.defaultRenderer = function(value){
+    if (typeof value == 'undefined') {
+        return '&#160;';
+    }
+       if (typeof value == 'string' && value.length < 1){
+           return '&#160;';
+       }
+    //console.log(value);
+    return String.format('{0}',value);   
+};
+// as 'findbyId in roo...
+Ext.form.Form.prototype.stackFind = function(id)
+{
+    return this.findbyId(id);
+     
+};
+
+// This is in Roo???
+Ext.form.Hidden = function(config){
+    Ext.form.Hidden.superclass.constructor.call(this, config);
+};
+
+Ext.extend(Ext.form.Hidden, Ext.form.TextField, {
+    fieldLabel: '',
+    inputType: 'hidden',
+    width: 50,
+    allowBlank: true,
+    labelSeparator: '',
+     
+    hidden: true,
+    itemCls : 'x-form-item-display-none'
+
+
+});
+Ext.form.DateField.prototype.getValue = function(fmt) {
+    var r = this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || '';
+    if (typeof(fmt) == 'undefined') {
+        return r;
+    }
+    if (typeof(r) == 'string') {
+        return '';
+    }
+    return r.format(fmt);
+};
+
+//<script type="text/Javascript">
+
+/**
+ * @class Ext.form.FormButton
+ * @extends Ext.Button
+ * Single checkbox field.  Can be used as a direct replacement for traditional checkbox fields.
+ * @constructor
+ * Creates a new Checkbox
+ * @param {Object} config Configuration options
+ */
+Ext.form.FormButton = function(config){
+    this.config = config;
+    Ext.form.FormButton.superclass.constructor.call(this, config);
+    
+    
+};
+Ext.extend(Ext.form.FormButton, Ext.form.Field, {
+    config : false,
+    labelSeparator: '',
+    defaultAutoCreate : { tag: 'input', type: 'hidden'},
+    onRender : function(ct, position){
+        Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
+        // remove label..
+        var p = Ext.get(this.container.findParentNode('div'));
+        var ch = p.child('label');
+        if (ch) {
+            ch.remove();
+        }
+        
+        // add our button..
+        var bc = this.container.createChild({ tag : 'div' });
+          
+        new Ext.Button(bc, this.config);
+        
+    }
+    
+    
+});
+
+Roo.Toolbar.prototype.hide = function()
+{
+    this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
+    this.el.child('div').hide();
+};
+Roo.Toolbar.prototype.show = function()
+{
+    this.el.child('div').show();
+};
+
+/* what's this for??? - I think to add x-toolbar-td - is it needed???*/
+Roo.Toolbar.prototype.nextBlock = function(){
+  
+    var td = document.createElement('td');
+    this.tr.appendChild(td);
+    td.className = 'x-toolbar-td';
+    return td;
+    
+};
diff --git a/widgets/FieldSetEx.js b/widgets/FieldSetEx.js
new file mode 100644 (file)
index 0000000..6c0ba4d
--- /dev/null
@@ -0,0 +1,143 @@
+//<script type="text/javascript">
+
+
+Ext.form.FieldSetEx = function(config){
+    Ext.form.FieldSetEx.superclass.constructor.call(this, config);
+   /* if (!this.id) {
+        this.id = Ext.id();
+    }*/
+    this.addEvents({
+        expand: true
+    });
+};
+
+Ext.extend(Ext.form.FieldSetEx, Ext.form.FieldSet, {
+    collapseGroup : false,
+    expanded: true,
+    outer: false,
+    fs : false,
+    name : false,
+    hiddenEl: false,
+    defaultAutoCreate :  {tag: 'fieldset', cn: { tag:'legend' }},
+    defaultBorder  : '',
+
+    onRender : function(ct, position)
+    {
+       
+        if(this.el){ 
+            this.el = Roo.get(this.el);
+        }else {
+            // wrap the fieldset up so wee can  mask the contents..
+        
+            var cfg = this.getAutoCreate();
+            this.fs = ct.createChild(cfg, position);
+            if(this.style){
+                this.fs.applyStyles(this.style);
+            }
+            // add the hidden value 
+            if (this.name) {
+                this.hiddenEl = this.fs.createChild({
+                        tag: 'input' , 
+                        type: 'hidden', 
+                        name : this.name,
+                        value : '',
+                        cls: 'x-form-item-display-none'
+                });
+            }
+            
+            this.el = this.fs.createChild({tag: 'div' });
+            this.el.setVisibilityMode(Ext.Element.DISPLAY);
+        }
+        
+        
+        
+        Ext.form.FieldSet.superclass.onRender.call(this, ct, position);
+        
+        if(this.legend){
+            this.setLegend(this.legend);
+        }
+        if (this.innerHTML) {
+             this.el.createChild({ tag: 'div', cls: 'x-form-item' , html : this.innerHTML });
+         
+        }
+
+        var l = this.fs.child('legend');
+        l.setStyle(
+            'background',
+            'transparent url('+ Ext.rootURL + '/images/default/menu/chk-sprite.gif)  no-repeat scroll 0 0'
+        );
+        
+        l.setStyle('padding', '0 5 0 20');
+        l.setStyle('cursor', 'pointer');
+        l.on('click', function() {
+            this.setExpand(!this.expanded);
+            
+            // fire event..
+        }, this);
+        
+        var t = this;
+        // not sure why but it always shows up visiable...
+        setTimeout(function(){
+            t.expand(t.expanded);
+        }, 10);
+       
+    },
+    setExpand : function(state) // expand/collapse this, and reflect on others...
+    {
+        this.expanded = state;
+        this.expand(state);
+        this.collapseOthers(state);
+        this.fireEvent('expand', this, state);
+    },
+    expand : function(state)
+    {
+        this.expanded = state;
+        var l = this.fs.child('legend');
+        l.setStyle('background-position', state ?  '0 -16px': '0 0');
+        //l.setStyle(
+        //    'background','transparent url('+ Ext.rootURL + 'images/default/menu/' +
+        //        (state ? '' : 'un') + 'checked.gif) no-repeat scroll 0 0'
+        //);
+        this.fs.setStyle('padding', state && !this.defaultBorder.length ? '10 10 5' : '0 10');
+        this.fs.setStyle('border', state ? this.defaultBorder : 'none');
+        var d = this.fs.query('div');
+        if (this.hiddenEl) {
+            this.hiddenEl.dom.value = state * 1;
+        }
+        this.el.setVisible(state);
+        //Ext.each(d, function(e) {
+        //    Ext.get(e).setVisibilityMode(Ext.Element.DISPLAY);
+        //    Ext.get(e).setVisible(state);
+        //});
+        
+        
+    },
+    
+    collapseOthers:  function(state)
+    {
+        if (!this.form) { // needs context
+            return;
+        }
+        var _this = this;
+        Ext.each(this.form.allItems, function(f){
+            
+            
+            if (f.collapseGroup &&  f.collapseGroup == _this.collapseGroup && _this.name != f.name) {
+                // toggle it!!!
+                f.expand(!state);
+                if (!state) {
+                    return false; // no more... (if we unexpand the only the first get's expanded..
+                }
+            }
+        });
+    },
+    
+    
+    setLegend : function(text){
+        if(this.rendered){
+            var l = this.fs.child('legend');
+            l.update(text);
+             
+        }
+    }
+});
\ No newline at end of file
diff --git a/widgets/FormGrid.js b/widgets/FormGrid.js
new file mode 100644 (file)
index 0000000..fac506f
--- /dev/null
@@ -0,0 +1,130 @@
+//<script type="text/javascript">
+/**
+ * @class Ext.form.Checkbox
+ * @extends Ext.form.Field
+ * Single checkbox field.  Can be used as a direct replacement for traditional checkbox fields.
+ * @constructor
+ * Creates a new Checkbox
+ * @param {Object} config Configuration options
+ */
+Ext.form.FormGrid = function(config){
+    Ext.form.FormGrid.superclass.constructor.call(this, config);
+     
+};
+
+Ext.extend(Ext.form.FormGrid, Ext.form.Field,  {
+    /**
+     * @cfg {Number} width  - mostly ignored
+     */
+    width : 100,
+    /**
+     * @cfg {Number} height - used to restrict height of image..
+     */
+    width : 50,
+     /**
+     * @cfg {String} grid The embeded grid...
+     */
+    grid : false, 
+    /**
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     */
+    focusClass : undefined,
+    /**
+     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
+     */
+    fieldClass: 'x-form-field',
+    /**
+     * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
+     */
+    checked: false,
+    /**
+     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "checkbox", autocomplete: "off"})
+     */
+   // defaultAutoCreate : { tag: 'div' },
+     defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
+    /**
+     * @cfg {String} addTitle Text to include for adding a title.
+     */
+     addTitle : false,
+    //
+    onResize : function(){
+        Ext.form.Field.superclass.onResize.apply(this, arguments);
+        
+    },
+
+    initEvents : function(){
+        // Ext.form.Checkbox.superclass.initEvents.call(this);
+        // has no events...
+       
+    },
+
+
+    getResizeEl : function(){
+        return this.wrap;
+    },
+
+    getPositionEl : function(){
+        return this.wrap;
+    },
+
+    // private
+    onRender : function(ct, position){
+        
+        this.style = this.style || '';
+        var style = this.style;
+        delete this.style;
+        
+        Ext.form.DisplayImage.superclass.onRender.call(this, ct, position);
+        this.wrap = this.el.wrap({cls: 'x-menu-check-item '}); // not sure why ive done thsi...
+        this.viewEl = this.wrap.createChild({ tag: 'div' });
+        if (style) {
+            this.viewEl.applyStyles(style);
+        }
+        if (this.width) {
+            this.viewEl.setWidth(this.width);
+        }
+        if (this.height) {
+            this.viewEl.setHeight(this.height);
+        }
+        //if(this.inputValue !== undefined){
+        //this.setValue(this.value);
+        
+        
+        this.grid = new Roo.grid.EditorGrid(this.viewEl, this.grid);
+        /*
+        var layout = Roo.BorderLayout.create({
+            center: {
+                margins:{left:3,top:3,right:3,bottom:3},
+                panels: [new Roo.GridPanel(grid)]
+            }
+        }, 'grid-panel');
+        */
+
+        this.grid.render();
+
+        
+    },
+
+    // private
+    initValue : Ext.emptyFn,
+
+    /**
+     * Returns the checked state of the checkbox.
+     * @return {Boolean} True if checked, else false
+     */
+    
+    /**
+     * Sets the value of the item. 
+     * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
+     */
+    setValue : function(v){
+        //this.value = v;
+        
+        Roo.form.FormGrid.superclass.setValue.call(this, v);
+    }
+    
+     
+    
+    
+});
\ No newline at end of file
diff --git a/widgets/GnumericWriter.js b/widgets/GnumericWriter.js
new file mode 100644 (file)
index 0000000..44f02a1
--- /dev/null
@@ -0,0 +1,809 @@
+//<script type="text/javascript">
+
+/*
+usage:
+
+writer = new GnumericWriter(rooturl + '/FlexyShipping/templates/spreadsheets/base.gnumeric.xml', function(w) {
+    w.setSheetName(document.getElementById('title').childNodes[0].nodeValue);
+
+    w.writeString(0,0, 'Summary for ' + document.getElementById('title').childNodes[0].nodeValue + 
+                ' as of ' + document.getElementById('date').childNodes[0].nodeValue);
+
+     
+    
+    w.importGrid(grid, rows)
+    
+    // post the form...
+    return true; // will post the form.. false will stop it..
+
+});
+
+
+cell information for auto tables:
+
+<td xls:type="int|float|string">  (string default)
+
+<td xls:Format="#,##0.00"  (2 decimal places) on a float
+<td xls:Format="0.00%">   percentage with float
+<td xls:Format="0%">   percentage (with no float)
+
+
+
+-  added so the editor works..
+
+*/
+function GnumericWriter(cfg) { }
+   
+/*
+function GnumericWriter(cfg) 
+{
+        //alert(template);
+    Roo.apply(this,cfg);
+    var _this = this;
+    if (!this.targetURL.length) {
+        this.targetURL = baseURL + '/GnumericToExcel';
+   }
+    
+    if (!GnumericWriter.postform) {
+        GnumericWriter.postform = Roo.get(document.body).createChild({
+            tag: 'form', 
+            method: 'POST', 
+            //defaultaction : baseURL + '/GnumericToExcel',
+            target : '_new'
+        });
+        
+        GnumericWriter.postxml = GnumericWriter.postform.createChild({
+            tag: 'input', type: 'hidden', name: 'xml'
+        });
+        GnumericWriter.postformat = GnumericWriter.postform.createChild({
+            tag: 'input', type: 'hidden', name: 'format', value: 'xls'
+        });
+        GnumericWriter.postdebug = GnumericWriter.postform.createChild({
+            tag: 'input', type: 'hidden', name: 'debug', value: ''
+        });
+    }
+    
+    
+    
+    Roo.Ajax.request({
+        url : this.template,
+        method : 'GET',
+        success : function(resp, opts) {
+            _this.init(resp.responseXML);
+        }
+    });
+}
+GnumericWriter.postform = false;
+GnumericWriter.postxml = false;
+GnumericWriter.postformat = false;
+GnumericWriter.postdebug = false;
+
+Roo.apply(GnumericWriter.prototype, {
+    format : 'xls',
+    debug: 0,
+    targetURL : '',
+    afterInit: false,
+    sheetName : 'unnamed',
+    filename  : 'test.gnumeric',
+    init : function(resp) {
+        if (!resp) {
+            alert('Failed to load ' + this.template);
+        }
+        
+        this.gnumeric        = resp;
+        
+        //alert(this.gnumeric);
+        //gmr:Sheet
+        var g = this.gnumeric;
+        this.worksheet       = Roo.isIE ? g.getElementsByTagName('gmr:Sheet')[0] :  g.getElementsByTagNameNS('*','Sheet')[0];
+        this.workbook        = Roo.isIE ? g.getElementsByTagName('gmr:Workbook')[0] :  this.gnumeric.getElementsByTagNameNS('*','Workbook')[0];
+        this.worksheet_cells = Roo.isIE ? g.getElementsByTagName('gmr:Cells')[0] :  this.worksheet.getElementsByTagNameNS('*','Cells')[0];
+        this.merges          = false;
+        this.widths          = new Array();
+         
+        
+        // set some defaults....
+        this.setSheetName(this.sheetName);
+        if (!this.afterInit) {
+            alert('GnumericWriter: no afterInit defined');
+            return;
+        }
+        if (false === this.afterInit(this)) {
+            return;
+        };
+        this.writeImages(); // which in turn posts the form..
+    },
+    
+    
+    
+    
+    toXML : function () 
+    {
+        if (Roo.isIE) {
+            return this.gnumeric.xml;
+        }
+        var ser = new XMLSerializer();
+        return ser.serializeToString(this.gnumeric);
+    },
+    postForm : function ()  // post a form wit the contents..?
+    {
+        var form = GnumericWriter.postform.dom;
+        //alert(form.action); 
+        if (!form) {
+            alert('GnumericWriter: form not loaded yet?');
+            return;
+        }
+        GnumericWriter.postxml.dom.setAttribute('value', this.toXML());
+        GnumericWriter.postdebug.dom.setAttribute('value', this.debug);
+        GnumericWriter.postformat.dom.setAttribute('value', this.format);
+        
+        
+        
+        form.setAttribute('action', this.targetURL + '/' + this.filename);
+        //alert( form.getAttribute('action'));
+        form.submit();
+         
+        
+    },
+
+
+    setFileName : function(name) 
+    {
+        this.filename = name;
+    },
+    
+    setSheetName: function(name) 
+    {
+        // this doesnt work yet!!!
+        //this.worksheet.setAttribute('name',name);
+    },
+    
+    
+
+    setColumnWidth: function(col, width)
+    {
+        // <gmr:Cols DefaultSizePts="48">
+        //   <gmr:ColInfo No="1" Unit="67.5" MarginA="2" MarginB="2" HardSize="1"/>
+        // < /gmr:Cols>
+       var g = this.gnumeric;
+        var cols = Roo.isIE ? g.getElementsByTagName('gmr:Cols')[0] :  this.gnumeric.getElementsByTagNameNS('*','Cols')[0];
+        var ri = this.gnumeric.createElement('gmr:ColInfo');
+        ri.setAttribute('No', col);
+        ri.setAttribute('Unit', width);
+        ri.setAttribute('MarginA', 2);
+        ri.setAttribute('MarginB', 2);
+        ri.setAttribute('HardSize', 1);
+        cols.appendChild(ri);
+        this.widths[col+0] = width+0;
+    },
+     
+    setRowHeight: function(row,height)
+    {
+    //<gmr:Rows DefaultSizePts="12.75">
+    //   <gmr:RowInfo No="2" Unit="38.25" MarginA="0" MarginB="0" HardSize="1"/>
+    //  < /gmr:Rows>
+        var g = this.gnumeric;
+        var rows = Roo.isIE ? g.getElementsByTagName('gmr:Rows')[0] :  this.gnumeric.getElementsByTagNameNS('*','Rows')[0];
+        var ri = this.gnumeric.createElement('gmr:RowInfo');
+        ri.setAttribute('No', row);
+        ri.setAttribute('Unit', height);
+        ri.setAttribute('MarginA', 0);
+        ri.setAttribute('MarginB', 0);
+        ri.setAttribute('HardSize', 1);
+        rows.appendChild(ri);
+    },
+     
+    
+    writeString: function (x,y,string) 
+    {
+    
+        var cell = this.gnumeric.createElement('gmr:Cell');
+        cell.setAttribute('Row',y);
+        cell.setAttribute('Col',x);
+        cell.setAttribute('ValueType',60); // a string.
+
+        var cell_value = this.gnumeric.createTextNode(string);
+        cell.appendChild(cell_value);
+        this.worksheet_cells.appendChild(cell);
+    },
+   // not sure what this is for..  
+    mergeRegion: function(col1,row1,col2,row2)
+    {
+        var cell = this.gnumeric.createElement('gmr:Merge');
+        var cell_value = this.gnumeric.createTextNode( 
+            this.colRowToName(row1,col1) + ':' + this.colRowToName(row2,col2)
+        );
+        cell.appendChild(cell_value);
+        
+        //var merges = this.gnumeric.getElementsByTagNameNS('*','MergedRegions');
+        var g = this.gnumeric;
+        if (!this.merges) {
+            this.merges = this.gnumeric.createElement('gmr:MergedRegions');
+            var sl = Roo.isIE ? g.getElementsByTagName('gmr:SheetLayout')[0] : this.gnumeric.getElementsByTagNameNS('*','SheetLayout')[0];
+
+            this.worksheet.insertBefore(this.merges,sl);
+        }
+        this.merges.appendChild(cell);
+    
+    },
+    
+    //
+     // -- you may want to load with all the data.. if paged...
+     // grid = grid object
+     // row = grid.getSelectionModel.getSelected()
+    // or
+     // row = grid.getDataSource().getRange(0, grid.getDataSource().getCount());
+     // 
+     //
+    
+    
+    importGrid: function(cfgIn) 
+    {
+        var _this = this;
+        var cfg = {
+            grid: false,
+            rows : [],
+            rowOffset : 0,
+            colOffset : 0,
+            colModel : cfgIn.grid.getColumnModel().config
+        };
+        Roo.apply(cfg, cfgIn);
+        
+        
+        if (!cfg.grid) {
+            alert('no grid selected.');
+            return;
+        }
+         
+        var _ds = cfg.grid.getDataSource();
+         
+        // get the grid column model.. - and use for headings..
+        
+        Roo.each(cfg.colModel, function(c,col) {
+            _this.setColumnWidth(col,c.width);
+            //this.setRowHeight(0, 0 + col.getAttribute('xls:height'));
+            var cell = _this.gnumeric.createElement('gmr:Cell');
+            cell.setAttribute('Row',0);
+            cell.setAttribute('Col',col);
+            cell.setAttribute('ValueType',60); // string!!!!
+            var cell_value = _this.gnumeric.createTextNode(c.header);
+            cell.appendChild(cell_value);
+            _this.worksheet_cells.appendChild(cell);
+        });
+        
+        
+        Roo.each(cfg.rows, function(r,rownum) {
+           
+            Roo.each(cfg.colModel, function(c,col) {
+                    var val = r.get(c.dataIndex);
+                    if (typeof(val) == 'undefined') {
+                        return;
+                    }
+                    
+                    var cell = _this.gnumeric.createElement('gmr:Cell');
+                    cell.setAttribute('Row',rownum+1);
+                    cell.setAttribute('Col',col);
+                    
+                    if (c.gRenderer) {
+                        // then - just use the datasource
+                        //cell.setAttribute('ValueType',60); // string!!!!
+                        if (false === c.gRenderer(_this, val, r, cell, rownum+1, col)) {
+                            return;
+                        }
+                        //cell.appendChild(cell_value);
+                        _this.worksheet_cells.appendChild(cell);
+                        var lb = _this.gnumeric.createTextNode('\n');
+                        _this.worksheet_cells.appendChild(lb);
+                        return;
+                    }
+                    // otherwise use the details..
+                    
+                    
+                    
+                    var cell_cfg = _ds.getAt(0).fields.get(c.dataIndex);
+                    switch(cell_cfg.type) {
+                        case 'int': 
+                            cell.setAttribute('ValueType',30); 
+                            break;
+                        case 'float': 
+                            cell.setAttribute('ValueType',40); 
+                            break;
+                        case 'date':  
+                            cell.setAttribute('ValueType',30); 
+                            cell.setAttribute('ValueFormat','d/mmm/yyyy');
+                            val = '' + Math.round((val.getTime() - 
+                                Date.UTC(1899,11,30)) / (24 * 60 * 60 * 1000));
+                            break;
+                        default: // string
+                            cell.setAttribute('ValueType',60);
+                            break;
+                    }
+                    
+                    var cell_value = _this.gnumeric.createTextNode(val);
+                    cell.appendChild(cell_value);
+                    _this.worksheet_cells.appendChild(cell);
+                    var lb = _this.gnumeric.createTextNode('\n');
+                    _this.worksheet_cells.appendChild(lb);
+            });
+           
+        });
+        
+         
+        
+          
+    },
+    
+    
+    newStyle: function(cfg) 
+    {
+        return new GnumericWriter.Style(this, cfg);
+    },
+    
+    
+    
+    colRowToName: function(row,col)
+    {
+        // we dont support > 26 cols yet!
+        
+        return String.fromCharCode(65+col) + (row + 1);
+    },
+    //
+     // writeImages([
+     //   { row: 0, col: 0, url: xxx, data: xxx, width: xxx, height: yyy }
+     // ]);
+     // 
+     ///
+    writeImages: function() 
+    {
+        this.images = this.images ||  [];
+        var ar = this.images;
+        if (!ar.length) {
+            this.postForm();
+            return;
+        }
+        Roo.MessageBox.show({
+           title: 'Please wait...",
+           msg: "Adding Images...",
+           width:350,
+           progress:true,
+           closable:false
+          
+        });
+        var i =0;
+        var _this = this;
+        var wis = function () {
+            if (i == ar.length) {
+                Roo.MessageBox.hide();
+                _this.postForm();
+                return;
+            }
+            Roo.MessageBox.updateProgress( 
+                (i+1)/ar.length,  'Adding Image ' + (i+1) +  ' of ' + ar.length 
+            );
+            
+             
+            var c = ar[i];
+            i++;
+            Roo.Ajax.request({
+                url : c.url,
+                method : 'GET',
+                success : function(resp, opts) {
+                    c.data = resp.responseText;
+                    _this.writeImage(c);
+                    wis();
+                },
+                failure: function()
+                {
+                    // error condition!?!?
+                    wis();
+                }
+                
+            });
+            
+            
+            
+        };
+        wis();
+        
+      
+      
+    },
+    images : false,
+    addImage: function(cfg) {
+        this.images = this.images ||  [];
+        this.images.push(cfg);
+    },
+    
+    writeImage: function(cfg) 
+    {
+        
+        // our default height width is 50/50 ?!
+        //console.log('w='+width+',height='+height);
+                //        <gmr:Objects>
+        this.setRowHeight(cfg.row,cfg.height);
+        var g =  this.gnumeric;
+        var objs = Roo.isIE ? g.getElementsByTagName('gmr:Objects')[0] : this.gnumeric.getElementsByTagNameNS('*','Objects')[0];
+        var soi = this.gnumeric.createElement('gmr:SheetObjectImage');
+        
+        //<gmr:SheetObjectImage 
+        //      ObjectBound="A3:J8" 
+        //      ObjectOffset="0.375 0.882 0.391 0.294" 
+        //      ObjectAnchorType="16 16 16 16" 
+        //      Direction="17" 
+        //      crop-top="0.000000" 
+        //      crop-bottom="0.000000" 
+        //      crop-left="0.000000" 
+        //      crop-right="0.000000">
+                
+                
+        //alert(gnumeric_colRowToName(row,col));
+               
+        // this is where we really have fun!!!... 
+        // since our design currently assumes the height is enough to fit
+        // stuff in, we only really need to work out how wide it has to be..
+        
+        // note we should probably use centralized calcs if it fits in the first cell!
+        
+        // step 1 - work out how many columns it will span..
+        // lets hope the spreadsheet is big enought..
+        var colwidth = this.widths[cfg.col];
+        //
+        //for (var endcoll=cfg.col;endcol <100; endcol++) {
+         //   if (!this.widths[endcol]) {
+          //      this.widths[endcol] = 100; // eak fudge
+         //   }
+         //   colwidth += this.widths[endcol];
+         //   if (colwidth > cfg.width) {
+         //       break;
+         //   }
+       // }
+        //
+        soi.setAttribute('ObjectBound',
+            this.colRowToName(cfg.row,cfg.col)
+        );
+            //gnumeric_colRowToName(row,col) + ':' + gnumeric_colRowToName(row+1,col+1));
+            //this.colRowToName(cfg.row,cfg.col) + ':' + this.colRowToName(cfg.row,endcol));
+     
+        var ww = 0.01; // offset a bit...
+        var hh = 0.01; //
+        
+        // cfg/widths == % of cell taken up..
+        // 1/1 = all of image.. so we should say '1'
+        // 50/100 = 50%  -> say '0.5'
+        //  1/100 => 1% say 0.01 ?
+        
+        var ww2 = (cfg.width *0.1/ this.widths[cfg.col]*0.1);
+        var hh2 = 0.99;
+        
+        var offset_str = ww + ' '  + hh + ' ' + ww2 + ' '+hh2;
+        //console.log(offset_str );
+        //alert(offset_str);
+        soi.setAttribute('ObjectOffset', offset_str);
+        soi.setAttribute('ObjectAnchorType','16 16 16 16');
+        soi.setAttribute('Direction','17');
+        soi.setAttribute('crop-top','0.000000');
+        soi.setAttribute('crop-bottom','0.000000');
+        soi.setAttribute('crop-left','0.000000');
+        soi.setAttribute('crop-right','0.000000');
+                // <Content image-type="jpeg" size-bytes="3900">......  < / Content>
+        var content = this.gnumeric.createElement('Content');
+        content.setAttribute('image-type','jpeg');
+         
+        content.setAttribute('size-bytes', cfg.data.length);
+      
+        var body = this.gnumeric.createTextNode(cfg.data) ;
+        content.appendChild(body);
+        soi.appendChild(content);
+        objs.appendChild(soi);
+        return true;
+                //< /gmr:SheetObjectImage>
+                // < /gmr:Objects>
+
+    },
+  
+    cleanHtml: function(str) 
+    {
+        var ret = str;
+        ret = ret.replace(/&nbsp;/g,'.');
+        ret = ret.replace(/\n/g,'.');
+        ret = ret.replace(/\r/g,'.');
+        var i;
+        while (-1 != (i = ret.indexOf(unescape('%A0')))) {
+            ret = ret.substring(0,i) + ' ' + ret.substring(i+1,str.length);
+        }
+        return ret;
+    
+    }
+});
+
+
+GnumericWriter.Style = function (gnumeric,cfg) 
+    {
+        cfg = cfg || {}; 
+        
+        this.gnumeric = gnumeric.gnumeric;
+        
+        this.HAlign             = 1;
+        this.VAlign             = 1;
+        this.WrapText           = 0;  // set to 1 for wrapping...
+        this.ShrinkToFit        = 0;
+        this.Rotation           = 0;
+        this.Shade              = 0;  // set to 1 for fill?
+        this.Indent             = 0;
+        this.Locked             = 0;
+        this.Hidden             = 0;
+        this.Fore               = '0:0:0';
+        this.Back               = 'FFFF:FFFF:FFFF';
+        this.PatternColor       = '0:0:0';
+        this.Format             = 'General';
+        // dubious - font as it's own objecT???
+        this.FontUnit           = 10;
+        this.FontBold           = 0;
+        this.FontItalic         = 0;
+        this.FontUnderline      = 0;
+        this.FontStrikeThrough  = 0;
+        this.FontName           = 'Sans'; // or .. ."Courier New"
+        // borders
+        this.Style              = 0; // set to 1 to set all styles...
+        this.StyleColor         = '';
+        
+        this.TopStyle           = 0;
+        this.TopStyleColor      = '';
+        this.BottomStyle        = 0;
+        this.BottomStyleColor   = '';
+        this.LeftStyle          = 0;
+        this.LeftStyleColor     = '';
+        this.RightStyle         = 0;
+        this.RightStyleColor    = '';
+        Roo.apply(this, cfg);
+        
+        
+        
+        // methods...
+         
+}
+Roo.apply(   GnumericWriter.Style.prototype, {
+    
+    
+    toString : function() 
+    {
+        var ret = '';
+        t = this;
+        for (var i in t) {
+            if ((t[i]+'').match(/function/)) { 
+                continue; 
+            }
+            ret += i + '=' +  t[i] + '\n';
+        }
+        return ret;
+        
+    },
+    
+    rgbToHex : function(str) 
+    {
+        str = str.replace(/[^0-9,]+/g,'');
+        
+        var bits = str.split(',');
+        return '' + (bits[0]*256).toString(16) +
+            ':'  +
+            ((bits.length > 2) ? (bits[1]*256).toString(16) : '00') +
+            ':'  +
+            ((bits.length > 2) ? (bits[2]*256).toString(16) : '00');
+    
+    },
+    
+    debugNode : function(node)
+    {   
+        var s = document.defaultView.getComputedStyle(node, '');
+        
+        
+        var str = '';
+        for (var i in s) {
+            if ((s[i] + '').match(/function/)) { continue; }
+            str += i + '=' + s[i] + '<br>';
+        }
+        document.write('xls:debug = Note, outputing this, will skew the results \n' +  str);
+        return;
+    },
+       
+    setFrom : function(node) 
+    {
+        var ret = false;
+        var style = document.defaultView.getComputedStyle(node, '');
+        
+       
+        
+        var sides = new Array( 'Left' , 'Right', 'Top' , 'Bottom' );
+        for (var i in sides) {
+            var side = sides[i];
+            
+            if (style['border'+side+'Style'] == 'solid') {
+                this[side+'Style']           = 1;
+                this[side+'StyleColor']      = this.rgbToHex(style['border'+side+'Color']);
+                ret = true;
+            }   
+        }
+        
+        // alignment:
+        switch(style.textAlign) {
+            case 'center':
+                this.HAlign             = 8;
+                ret = true;
+                break;
+            case 'start':
+                this.HAlign             = 0;
+                ret = true;
+                break;
+            default:
+                this.HAlign             = 1;
+                ret = true;
+                break;
+        }
+         
+        if (style.verticalAlign  != 'middle') {
+            // eak what?
+            this.VAlign             = 1;
+            ret = true;
+        }
+        if ((style.backgroundColor != 'rgb(255, 255, 255)') && 
+            style.backgroundColor.match(/rgb/))
+        {
+            this.Back               = this.rgbToHex(style.backgroundColor);    
+            this.Shade              = 1;  // set to 1 for fill?
+            ret = true;
+        }
+        if ((style.color != 'rgb(0, 0, 0)') && 
+            style.color.match(/rgb/))
+        {
+            this.Fore               = this.rgbToHex(style.color);    
+            ret = true;
+        }
+        
+        // font stuff.. - only valid if you specify a specific font!
+        if (node.getAttribute('xls:debug')) {
+            alert( style['fontFamily'] + ' : ' + (  (style.fontFamily + '').match(/xls/) ? 'isxls' : 'not xls'));
+        }
+        if (style.fontFamily.match(/xls/)) {
+            
+            this.FontUnit           = style.fontSize.replace(/[^0-9.]+/g,'');
+            this.FontBold           = (style.fontWeight == 'bold') ? 1 : 0;
+            this.FontItalic         = (style.fontStyle == 'italic') ? 1 : 0;
+            //this.FontUnderline      = 0;
+            //this.FontStrikeThrough  = 0;
+            this.FontName           = style.fontFamily.split(',')[0];
+            ret = true;
+        }
+        
+        
+        
+        var t = this;
+        for (var i in t) {
+            if (node.getAttribute('xls:'+i)) {
+                this[i] = node.getAttribute('xls:'+i);
+                ret = true;
+            }
+        }
+        if (ret && this.Style > 0) {
+            this.TopStyle           = this.Style;
+            this.TopStyleColor      = this.StyleColor;
+            this.BottomStyle        = this.Style;
+            this.BottomStyleColor   = this.StyleColor;
+            this.LeftStyle          = this.Style;
+            this.LeftStyleColor     = this.StyleColor;
+            this.RightStyle         = this.Style;
+            this.RightStyleColor    = this.StyleColor;
+        }
+        if (node.getAttribute('xls:debug')) {
+            alert(node.innerHTML + ':' + ret + '\n' + this.toString());
+        }
+        if (node.getAttribute('xls:debug')) {
+            //alert(style.fontFamily);
+             GnumericWriter_Style_debugNode(node);
+        }
+        return ret;
+    },
+    
+    
+    add : function(startCol, startRow, endCol, endRow) 
+    {
+        
+        
+        //  <gmr:StyleRegion startCol="4" startRow="13" endCol="4" endRow="13">
+        //       <gmr:Style HAlign="1" VAlign="1" WrapText="1" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="0" Hidden="0" Fore="FFFF:0:0" Back="CCCC:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+        //         <gmr:Font Unit="8" Bold="0" Italic="1" Underline="0" StrikeThrough="0">Courier New</gmr:Font>
+        //         <gmr:StyleBorder>
+        //           <gmr:Top Style="0"/>
+        //           <gmr:Bottom Style="1" Color="0:0:0"/>
+        //           <gmr:Left Style="0"/>
+        //           <gmr:Right Style="1" Color="0:0:0"/>
+        //           <gmr:Diagonal Style="0"/>
+        //           <gmr:Rev-Diagonal Style="0"/>
+        //         </gmr:StyleBorder>
+        //       </gmr:Style>
+        //</gmr:StyleRegion>
+        
+        sr   = this.gnumeric.createElement('gmr:StyleRegion');
+        s    = this.gnumeric.createElement('gmr:Style');
+        f    = this.gnumeric.createElement('gmr:Font');
+        sb   = this.gnumeric.createElement('gmr:StyleBorder');
+        sbt  = this.gnumeric.createElement('gmr:Top');
+        sbb  = this.gnumeric.createElement('gmr:Bottom');
+        sbl  = this.gnumeric.createElement('gmr:Left');
+        sbr  = this.gnumeric.createElement('gmr:Right');
+        sbd  = this.gnumeric.createElement('gmr:Diagonal');
+        sbrd = this.gnumeric.createElement('gmr:Rev-Diagonal');
+        fn   = this.gnumeric.createTextNode(this.FontName);
+        
+        
+        sr.setAttribute('startCol',startCol);
+        sr.setAttribute('startRow',startRow);
+        sr.setAttribute('endCol',endCol);
+        sr.setAttribute('endRow',endRow);
+    
+         
+        s.setAttribute('HAlign',this.HAlign);
+        s.setAttribute('VAlign',this.VAlign);
+        s.setAttribute('WrapText',this.WrapText);
+        s.setAttribute('ShrinkToFit',this.ShrinkToFit);
+        s.setAttribute('Rotation',this.Rotation);
+        s.setAttribute('Shade',this.Shade);
+        s.setAttribute('Indent',this.Indent); 
+        s.setAttribute('Locked',this.Locked);
+        s.setAttribute('Hidden',this.Hidden);
+        s.setAttribute('Fore',this.Fore);
+        s.setAttribute('Back',this.Back);
+        s.setAttribute('PatternColor',this.PatternColor);
+        s.setAttribute('Format',this.Format);
+        
+        
+        f.setAttribute('Unit',    this.FontUnit );
+        f.setAttribute('Bold',   this.FontBold);
+        f.setAttribute('Italic',   this.FontItalic);
+        f.setAttribute('Underline',   this.FontUnderline);
+        f.setAttribute('StrikeThrough',   this.FontStrikeThrough);
+            
+        
+        
+        
+         
+        sbt.setAttribute('Style',  this.TopStyle);
+        if (this.TopStyle > 0) sbt.setAttribute('Color',  this.TopStyleColor);
+        
+        sbb.setAttribute('Style',  this.BottomStyle);
+        if (this.BottomStyle > 0) sbb.setAttribute('Color',  this.BottomStyleColor);
+        
+        sbl.setAttribute('Style',  this.LeftStyle);
+        if (this.LeftStyle > 0) sbl.setAttribute('Color',  this.LeftStyleColor);
+        
+        sbr.setAttribute('Style',  this.RightStyle);
+        if (this.RightStyle > 0) sbr.setAttribute('Color',  this.RightStyleColor);
+        
+        sbd.setAttribute('Style',  0);
+        sbrd.setAttribute('Style',  0);
+        
+        // now add them all together!!!
+        sb.appendChild(sbt);
+        sb.appendChild(sbb);
+        sb.appendChild(sbl);
+        sb.appendChild(sbr);
+        sb.appendChild(sbd);
+        sb.appendChild(sbrd);
+        s.appendChild(sb);
+        f.appendChild(fn);
+        s.appendChild(f);
+        sr.appendChild(s);
+        
+        // .. this will only hit the first occurance!!!
+        var g = this.gnumeric;
+        
+        var styles = Roo.isIE ? g.getElementsByTagName('gmr:Styles')[0] : this.gnumeric.getElementsByTagNameNS('*','Styles')[0];
+        
+        // and finally to the document..
+        styles.appendChild(sr);
+        
+    }
+});    
+       */
\ No newline at end of file
diff --git a/widgets/SecurePass.js b/widgets/SecurePass.js
new file mode 100644 (file)
index 0000000..b946dc6
--- /dev/null
@@ -0,0 +1,291 @@
+
+//<script type="text/Javascript">
+
+
+Ext.form.SecurePass = function(config) {
+       // these go here, so the translation tool can replace them..
+    this.errors = {
+               PwdEmpty: "Please type a password, and then retype it to confirm.",
+               PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
+               PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
+               PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
+               IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
+               FNInPwd: "Your password can't contain your first name. Please type a different password.",
+               LNInPwd: "Your password can't contain your last name. Please type a different password.",
+        TooWeak: "Your password is Too Weak."
+       },
+    this.meterLabel = "Password strength:";
+    this.pwdStrengths = ["Too Weak" , "Weak", "Medium", "Strong"];
+    Ext.form.SecurePass.superclass.constructor.call(this, config);
+}
+
+Ext.extend(Ext.form.SecurePass, Ext.form.TextField, {
+       /**
+        * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
+        * {
+        *  PwdEmpty: "Please type a password, and then retype it to confirm.",
+        *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
+        *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
+        *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
+        *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
+        *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
+        *  LNInPwd: "Your password can't contain your last name. Please type a different password."
+        * })
+        */
+       // private
+       errors : {},
+    
+    imageRoot: '/',
+       
+       /**
+        * @cfg {String/Object} Label for the strength meter (defaults to
+        * 'Password strength:')
+        */
+       // private
+       meterLabel : '',
+
+       /**
+        * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
+        * ['Weak', 'Medium', 'Strong'])
+        */
+       // private
+       pwdStrengths : [],
+
+       /**
+        * @cfg {String/Object} fieldsFilter A fieldsFilter spec, as [['field_name', 'error_id'], ...]
+        */
+       // private
+       fieldsFilter : [],
+
+       // private
+       strength : 0,
+
+       // private
+       _lastPwd : null,
+    
+       // private
+       kCapitalLetter : 0,
+       kSmallLetter : 1,
+       kDigit : 2,
+       kPunctuation : 3,
+
+    // private
+    initEvents : function(){
+        Ext.form.SecurePass.superclass.initEvents.call(this);
+               this.el.on('keyup', this.checkStrength, this, {buffer:50});
+       },
+
+       // private
+       onRender : function(ct, position){
+               Ext.form.SecurePass.superclass.onRender.call(this, ct, position);
+               this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
+               this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter '+this.triggerClass});
+                
+               this.trigger.createChild({
+            tag: 'div',  
+            style: {
+                'margin-bottom': '10px',
+                width: this.width + 'px'
+            },
+            cn: {
+                tag: 'div', 
+                style: {
+                    width: this.width + 'px',
+                    height: '9px',
+                    'background-image' : 'url(\''+this.imageRoot+'/password_meter_grey.gif\')',
+                    'background-position' : 'center center',
+                    'background-repeat': 'no-repeat'
+                },
+                cn : {
+                    //id: 'PwdMeter',
+                    tag: 'div',
+                    style:  {
+                        width: 0,
+                        height: '9px',
+                        'background-image': 'url(\''+this.imageRoot+'/password_meter.gif\')',
+                        'background-position': 'center center',
+                        'background-repeat': 'no-repeat',
+                        'font-size': '9px'
+                    }
+                }
+            }
+        });
+               if(this.hideTrigger){
+                       this.trigger.setDisplayed(false);
+               }
+               this.setSize(this.width||'', this.height||'');
+       },
+
+       // private
+       onDestroy : function(){
+               if(this.trigger){
+                       this.trigger.removeAllListeners();
+                       this.trigger.remove();
+               }
+               if(this.wrap){
+                       this.wrap.remove();
+               }
+               Ext.form.TriggerField.superclass.onDestroy.call(this);
+       },
+    
+       // private
+       checkStrength : function(){
+               var pwd = this.el.getValue();
+               if (pwd == this._lastPwd) {
+                       return;
+               }
+
+               var strength;
+               if (this.ClientSideStrongPassword(pwd)) {
+                       strength = 3;
+               } else if(this.ClientSideMediumPassword(pwd)) {
+                       strength = 2;
+               } else if(this.ClientSideWeakPassword(pwd)) {
+                       strength = 1;
+               } else {
+                       strength = 0;
+               }
+        var pm = this.trigger.child('div/div/div').dom;
+        
+               pm.style.width = (this.width/3) * strength +'px';
+               //if(this.pwdStrengths != null && strength > 0) {
+        pm.innerHTML = this.meterLabel + '&nbsp;'+ this.pwdStrengths[strength];
+               //} else {
+               //      pm.innerHTML = '';
+               //}
+
+               this._lastPwd = pwd;
+       },
+    reset : function(){
+        Ext.form.SecurePass.superclass.reset.call(this);
+        this._lastPwd = '';
+        var pm = this.trigger.child('div/div/div').dom;
+        pm.style.width = 0;
+        pm.innerHTML = '';
+    },
+    // private
+       validateValue : function(value){
+               if (!Ext.form.TextField.superclass.validateValue.call(this, value)){
+            return false;
+        }
+               if (value.length == 0) {
+            if (this.allowBlank) {
+                this.clearInvalid();
+                return true;
+            }
+            
+                       this.markInvalid(this.errors.PwdEmpty);
+            return false;
+               }
+               if ('[\x21-\x7e]*'.match(value)) {
+                       this.markInvalid(this.errors.PwdBadChar);
+            return false;
+               }
+               if (value.length < 6) {
+                       this.markInvalid(this.errors.PwdShort);
+            return false;
+               }
+               if (value.length > 16) {
+                       this.markInvalid(this.errors.PwdLong);
+            return false;
+               }
+        var strength;
+               if (this.ClientSideStrongPassword(value)) {
+                       strength = 3;
+               } else if(this.ClientSideMediumPassword(value)) {
+                       strength = 2;
+               } else if(this.ClientSideWeakPassword(value)) {
+                       strength = 1;
+               } else {
+                       strength = 0;
+               }
+        if (strength < 2) {
+                       this.markInvalid(this.errors.TooWeak);
+            return false;
+               }
+        /*
+               for (var index = 0; index < this.fieldsFilter.length; ++index) {
+                       filter = document.getElementById(this.fieldsFilter[index][0]).value;
+                       if (filter != '')
+                       {
+                               re = new RegExp(filter);
+                               if (re.test(value)) {
+                                       this.markInvalid(eval('this.errors.'+ this.fieldsFilter[index][1]));
+                                       return false;
+                               }
+                       }
+               }
+        */
+               return true;
+       },
+
+    // private
+       CharacterSetChecks : function(type){
+               this.type = type;
+               this.fResult = false;
+       },
+
+    // private
+       isctype : function(character, type){
+               switch (type) { //why needed break after return in js ? very odd bug
+                       case this.kCapitalLetter: if (character >= 'A' && character <= 'Z') { return true; } break;
+                       case this.kSmallLetter: if (character >= 'a' && character <= 'z') { return true; } break;
+                       case this.kDigit: if (character >= '0' && character <= '9') { return true; } break;
+                       case this.kPunctuation: if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) { return true; } break;
+                       default: return false;
+               }
+        
+       },
+
+    // private
+       IsLongEnough : function(pwd, size){
+               return !(pwd == null || isNaN(size) || pwd.length < size);
+       },
+
+    // private
+       SpansEnoughCharacterSets : function(word, nb){
+               if (!this.IsLongEnough(word, nb))
+               {
+                       return false;
+               }
+
+               var characterSetChecks = new Array(
+                       new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
+                       new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
+               for (var index = 0; index < word.length; ++index) {
+                       for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
+                               if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
+                                       characterSetChecks[nCharSet].fResult = true;
+                                       break;
+                               }
+                       }
+               }
+
+               var nCharSets = 0;
+               for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
+                       if (characterSetChecks[nCharSet].fResult) {
+                               ++nCharSets;
+                       }
+               }
+
+               if (nCharSets < nb) {
+                       return false;
+               }
+               return true;
+       },
+
+    // private
+       ClientSideStrongPassword : function(pwd){
+               return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
+       },
+
+    // private
+       ClientSideMediumPassword : function(pwd){
+               return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
+       },
+
+    // private
+       ClientSideWeakPassword : function(pwd){
+               return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
+       }
+})
\ No newline at end of file
diff --git a/widgets/StarField.js b/widgets/StarField.js
new file mode 100644 (file)
index 0000000..7745f71
--- /dev/null
@@ -0,0 +1,134 @@
+//<script type="text/javascript">
+/**
+ * @class Ext.form.Checkbox
+ * @extends Ext.form.Field
+ * Single checkbox field.  Can be used as a direct replacement for traditional checkbox fields.
+ * @constructor
+ * Creates a new Checkbox
+ * @param {Object} config Configuration options
+ */
+Ext.form.StarField = function(config){
+    Ext.form.StarField.superclass.constructor.call(this, config);
+     
+};
+
+Ext.extend(Ext.form.StarField, Ext.form.Field,  {
+     
+     /**
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     */
+    
+    /**
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     */
+    focusClass : undefined,
+    /**
+     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
+     */
+    fieldClass: 'x-form-field',
+    /**
+     * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
+     */
+    checked: false,
+    /**
+     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "checkbox", autocomplete: "off"})
+     */
+   // defaultAutoCreate : { tag: 'div' },
+     defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
+    /**
+     * @cfg {String} addTitle Text to include for adding a title.
+     */
+     addTitle : false,
+    //
+    onResize : function(){
+        Ext.form.Field.superclass.onResize.apply(this, arguments);
+        
+    },
+
+    initEvents : function(){
+        // Ext.form.Checkbox.superclass.initEvents.call(this);
+        // has no events...
+       
+    },
+
+
+    getResizeEl : function(){
+        return this.wrap;
+    },
+
+    getPositionEl : function(){
+        return this.wrap;
+    },
+
+    // private
+    onRender : function(ct, position){
+        
+        this.style = this.style || '';
+        var style = this.style;
+        var _this= this;
+        delete this.style;
+        
+        Ext.form.StarField.superclass.onRender.call(this, ct, position);
+        this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
+        this.viewEl = this.wrap.createChild({ tag: 'img',  src: Roo.BLANK_IMAGE_URL });
+        
+        
+        this.viewEl.applyStyles('width:60px;height:15px;margin:3px;margin-left:1px;');
+        this.viewEl.applyStyles('background-image: url(' + rootURL +'/Pman/templates/images/fivestars.gif);' );
+        
+        
+        //if(this.inputValue !== undefined){
+        //this.setValue(this.value);
+        this.viewEl.on('mouseup',  function(e) { 
+            var xy = _this.viewEl.getXY();
+            var offset = Math.floor( (e.xy[0] - xy[0]) / 12.0) +1;
+            _this.setValue(offset);
+        });
+        this.viewEl.on('mousemove',  function(e) { 
+            var xy = _this.viewEl.getXY();
+            var offset = Math.floor( (e.xy[0] - xy[0]) / 12.0) +1;
+            _this.viewEl.setStyle('background-color', '#eee');
+            _this.viewEl.setStyle('background-position', '-' + (60 - (offset * 12)) + ' 0');
+        });
+        this.viewEl.on('mouseout',  function(e) { 
+            _this.setValue(_this.value);
+           
+        });
+        
+    },
+
+    // private
+    initValue : Ext.emptyFn,
+
+    /**
+     * Returns the checked state of the checkbox.
+     * @return {Boolean} True if checked, else false
+     */
+    
+    /**
+     * Sets the value of the item. 
+     * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
+     */
+    setValue : function(v){
+        
+        v = parseInt(v);
+        
+        if (isNaN(v)) {
+            v = 0;
+        }
+        v = v < 0 ? 0 : v;
+        v = v > 5 ? 5 : v;
+        
+        this.value = v;
+        this.viewEl.setStyle('background-color', '#fff');
+        this.viewEl.setStyle('background-position', '-' + (60 - (v * 12)) + ' 0');
+        
+        
+        Roo.form.StarField.superclass.setValue.call(this, v);
+    }
+    
+     
+    
+    
+});
\ No newline at end of file
diff --git a/widgets/lib.translation.json b/widgets/lib.translation.json
new file mode 100644 (file)
index 0000000..53cea07
--- /dev/null
@@ -0,0 +1,16 @@
+
+"SecurePass.js" : {
+        "Weak" : "Weak",
+        "Medium" : "Medium",
+        "Strong" : "Strong",
+        "Too Weak" : "Too Weak",
+        "Password strength:" : "Password strength:",
+        "Your password is Too Weak." : "Your password is Too Weak.",
+        "Please type a password, and then retype it to confirm." : "Please type a password, and then retype it to confirm.",
+        "Your password can't contain your last name. Please type a different password." : "Your password can't contain your last name. Please type a different password.",
+        "Your password can't contain your first name. Please type a different password." : "Your password can't contain your first name. Please type a different password.",
+        "Your password can't include the part of your ID. Please type a different password." : "Your password can't include the part of your ID. Please type a different password.",
+        "Your password must be at least 6 characters long. Please type a different password." : "Your password must be at least 6 characters long. Please type a different password.",
+        "Your password can't contain more than 16 characters. Please type a different password." : "Your password can't contain more than 16 characters. Please type a different password.",
+        "The password contains characters that aren't allowed. Please type a different password." : "The password contains characters that aren't allowed. Please type a different password."
+},
\ No newline at end of file