3 commits - lib/client lib/kolab_client_task.php lib/kolab_form.php lib/kolab_html.php lib/locale public_html/js public_html/skins

Aleksander Machniak machniak at kolabsys.com
Wed Sep 26 11:28:56 CEST 2012


 lib/client/kolab_client_task_domain.php           |   40 --
 lib/client/kolab_client_task_group.php            |   26 -
 lib/client/kolab_client_task_main.php             |    2 
 lib/client/kolab_client_task_resource.php         |   26 -
 lib/client/kolab_client_task_role.php             |   26 -
 lib/client/kolab_client_task_settings.php         |  419 ++++++++++++++++++----
 lib/client/kolab_client_task_user.php             |    6 
 lib/kolab_client_task.php                         |   61 +--
 lib/kolab_form.php                                |   61 ++-
 lib/kolab_html.php                                |    9 
 lib/locale/en_US.php                              |   35 +
 public_html/js/kolab_admin.js                     |  105 +++++
 public_html/skins/default/style.css               |   10 
 public_html/skins/default/templates/domain.html   |    2 
 public_html/skins/default/templates/group.html    |    2 
 public_html/skins/default/templates/resource.html |    2 
 public_html/skins/default/templates/role.html     |    2 
 public_html/skins/default/templates/type.html     |   18 
 public_html/skins/default/templates/user.html     |    2 
 public_html/skins/default/ui.js                   |    8 
 20 files changed, 615 insertions(+), 247 deletions(-)

New commits:
commit f0501590135f7f9d1222340ef023e1cfdaf27716
Author: Aleksander Machniak <alec at alec.pl>
Date:   Wed Sep 26 11:27:54 2012 +0200

    Types management (read-only), code improvements here and there

diff --git a/lib/client/kolab_client_task_domain.php b/lib/client/kolab_client_task_domain.php
index 8c8228c..3a9f6a9 100644
--- a/lib/client/kolab_client_task_domain.php
+++ b/lib/client/kolab_client_task_domain.php
@@ -118,7 +118,7 @@ class kolab_client_task_domain extends kolab_client_task
             $next  = $page < $pages ? $page + 1 : 0;
 
             $count_str = kolab_html::span(array(
-                'content' => $this->translate('domain.list.records', $start, $end, $count)), true);
+                'content' => $this->translate('list.records', $start, $end, $count)), true);
             $prev = kolab_html::a(array(
                 'class' => 'prev' . ($prev ? '' : ' disabled'),
                 'href'  => '#',
@@ -170,6 +170,7 @@ class kolab_client_task_domain extends kolab_client_task
             'foot'  => $foot,
         ));
 
+        $this->output->command('set_watermark', 'taskcontent');
         $this->output->set_env('search_request', $search_request ? base64_encode(serialize($search_request)) : null);
         $this->output->set_env('list_page', $page);
         $this->output->set_env('list_count', $count);
@@ -288,47 +289,10 @@ class kolab_client_task_domain extends kolab_client_task
 
         $form->set_title(kolab_html::escape($title));
 
-        $this->output->add_translation('domain.add.success', 'domain.edit.success', 'domain.delete.success');
-
         return $form->output();
     }
 
     /**
-     * Returns list of domain types.
-     *
-     * @return array List of domain types
-     */
-    public function domain_types()
-    {
-        $result = array(
-                1 => array(
-                        'key' => 'standard',
-                        'name' => 'Standard domain',
-                        'description' => 'A standard domain name space',
-                        'attributes' => array(
-                                'auto_form_fields' => array(),
-                                'form_fields' => array(
-                                        'associateddomain' => array(
-                                                'type' => 'list',
-                                            ),
-                                        'inetdomainbasedn' => array(
-                                                'optional' => 'true',
-                                            ),
-                                    ),
-                                'fields' => array(
-                                        'objectclass' => array(
-                                                'top',
-                                                'domainrelatedobject',
-                                            ),
-                                    ),
-                            ),
-                    ),
-            );
-        //console("domain_types() \$result", $result);
-        return $result;
-    }
-
-    /**
      * Users search form.
      *
      * @return string HTML output of the form
diff --git a/lib/client/kolab_client_task_group.php b/lib/client/kolab_client_task_group.php
index a628d50..fada00c 100644
--- a/lib/client/kolab_client_task_group.php
+++ b/lib/client/kolab_client_task_group.php
@@ -118,7 +118,7 @@ class kolab_client_task_group extends kolab_client_task
             $next  = $page < $pages ? $page + 1 : 0;
 
             $count_str = kolab_html::span(array(
-                'content' => $this->translate('group.list.records', $start, $end, $count)), true);
+                'content' => $this->translate('list.records', $start, $end, $count)), true);
             $prev = kolab_html::a(array(
                 'class' => 'prev' . ($prev ? '' : ' disabled'),
                 'href'  => '#',
@@ -162,6 +162,7 @@ class kolab_client_task_group extends kolab_client_task
             'foot'  => $foot,
         ));
 
+        $this->output->command('set_watermark', 'taskcontent');
         $this->output->set_env('search_request', $search_request ? base64_encode(serialize($search_request)) : null);
         $this->output->set_env('list_page', $page);
         $this->output->set_env('list_count', $count);
@@ -264,8 +265,6 @@ class kolab_client_task_group extends kolab_client_task
 
         $form->set_title(kolab_html::escape($title));
 
-        $this->output->add_translation('group.add.success', 'group.edit.success', 'group.delete.success');
-
         return $form->output();
     }
 
@@ -290,27 +289,6 @@ class kolab_client_task_group extends kolab_client_task
     }
 
     /**
-     * Returns list of group types.
-     *
-     * @return array List of group types
-     */
-    public function group_types()
-    {
-        if (!isset($_SESSION['group_types'])) {
-            $result = $this->api->post('group_types.list');
-            $list   = $result->get('list');
-
-            if (is_array($list)) {
-                $_SESSION['group_types'] = $list;
-            }
-        }
-
-        //console($_SESSION['group_types']);
-
-        return $_SESSION['group_types'];
-    }
-
-    /**
      * Users search form.
      *
      * @return string HTML output of the form
diff --git a/lib/client/kolab_client_task_main.php b/lib/client/kolab_client_task_main.php
index 8c50b10..bab614f 100644
--- a/lib/client/kolab_client_task_main.php
+++ b/lib/client/kolab_client_task_main.php
@@ -64,7 +64,7 @@ class kolab_client_task_main extends kolab_client_task
         $this->menu   = array();
 
         foreach ($this->_menu as $task => $api_task) {
-            if ($task != 'about' && !array_key_exists($api_task . '.list', $capabilities['actions'])) {
+            if ($task != 'about' && !array_key_exists($api_task . '.list', (array)$capabilities['actions'])) {
                 $task_class = 'kolab_client_task_' . $task;
                 if (!method_exists($task_class, 'is_enabled') || !$task_class::is_enabled($capabilities['actions'])) {
                     continue;
diff --git a/lib/client/kolab_client_task_resource.php b/lib/client/kolab_client_task_resource.php
index 9a1626d..8dde136 100644
--- a/lib/client/kolab_client_task_resource.php
+++ b/lib/client/kolab_client_task_resource.php
@@ -120,7 +120,7 @@ class kolab_client_task_resource extends kolab_client_task
             $next  = $page < $pages ? $page + 1 : 0;
 
             $count_str = kolab_html::span(array(
-                'content' => $this->translate('resource.list.records', $start, $end, $count)), true);
+                'content' => $this->translate('list.records', $start, $end, $count)), true);
             $prev = kolab_html::a(array(
                 'class' => 'prev' . ($prev ? '' : ' disabled'),
                 'href'  => '#',
@@ -164,6 +164,7 @@ class kolab_client_task_resource extends kolab_client_task
             'foot'  => $foot,
         ));
 
+        $this->output->command('set_watermark', 'taskcontent');
         $this->output->set_env('search_request', $search_request ? base64_encode(serialize($search_request)) : null);
         $this->output->set_env('list_page', $page);
         $this->output->set_env('list_count', $count);
@@ -292,8 +293,6 @@ class kolab_client_task_resource extends kolab_client_task
 
         $form->set_title(kolab_html::escape($title));
 
-        $this->output->add_translation('resource.add.success', 'resource.edit.success', 'resource.delete.success');
-
         return $form->output();
     }
 
@@ -332,25 +331,4 @@ class kolab_client_task_resource extends kolab_client_task
 
         return $form->output();
     }
-
-    /**
-     * Returns list of resource types.
-     *
-     * @return array List of resource types
-     */
-    public function resource_types()
-    {
-        if (isset($_SESSION['resource_types']) && !$this->devel_mode) {
-            return $_SESSION['resource_types'];
-        }
-
-        $result = $this->api->post('resource_types.list');
-        $list   = $result->get('list');
-
-        if (is_array($list) && !$this->devel_mode) {
-            $_SESSION['resource_types'] = $list;
-        }
-
-        return $list;
-    }
 }
diff --git a/lib/client/kolab_client_task_role.php b/lib/client/kolab_client_task_role.php
index 0363435..4640716 100644
--- a/lib/client/kolab_client_task_role.php
+++ b/lib/client/kolab_client_task_role.php
@@ -118,7 +118,7 @@ class kolab_client_task_role extends kolab_client_task
             $next  = $page < $pages ? $page + 1 : 0;
 
             $count_str = kolab_html::span(array(
-                'content' => $this->translate('role.list.records', $start, $end, $count)), true);
+                'content' => $this->translate('list.records', $start, $end, $count)), true);
             $prev = kolab_html::a(array(
                 'class' => 'prev' . ($prev ? '' : ' disabled'),
                 'href'  => '#',
@@ -162,6 +162,7 @@ class kolab_client_task_role extends kolab_client_task
             'foot'  => $foot,
         ));
 
+        $this->output->command('set_watermark', 'taskcontent');
         $this->output->set_env('search_request', $search_request ? base64_encode(serialize($search_request)) : null);
         $this->output->set_env('list_page', $page);
         $this->output->set_env('list_count', $count);
@@ -264,8 +265,6 @@ class kolab_client_task_role extends kolab_client_task
 
         $form->set_title(kolab_html::escape($title));
 
-        $this->output->add_translation('role.add.success', 'role.edit.success', 'role.delete.success');
-
         return $form->output();
     }
 
@@ -290,27 +289,6 @@ class kolab_client_task_role extends kolab_client_task
     }
 
     /**
-     * Returns list of role types.
-     *
-     * @return array List of role types
-     */
-    public function role_types()
-    {
-        if (isset($_SESSION['role_types']) && !$this->devel_mode) {
-            return $_SESSION['role_types'];
-        }
-
-        $result = $this->api->post('role_types.list');
-        $list   = $result->get('list');
-
-        if (is_array($list) && !$this->devel_mode) {
-            $_SESSION['role_types'] = $list;
-        }
-
-        return $list;
-    }
-
-    /**
      * Users search form.
      *
      * @return string HTML output of the form
diff --git a/lib/client/kolab_client_task_settings.php b/lib/client/kolab_client_task_settings.php
index 8eb5caa..061c65f 100644
--- a/lib/client/kolab_client_task_settings.php
+++ b/lib/client/kolab_client_task_settings.php
@@ -27,8 +27,12 @@ class kolab_client_task_settings extends kolab_client_task
     protected $ajax_only = true;
 
     protected $menu = array(
-        'type_list'  => 'types.list',
-        'type_add'   => 'type.add',
+        'type_list'  => 'type.list',
+        'type.add'   => 'type.add',
+    );
+
+    protected $form_element_types = array(
+        'text', 'select', 'multiselect', 'list', 'checkbox', 'password'
     );
 
     /**
@@ -36,22 +40,38 @@ class kolab_client_task_settings extends kolab_client_task
      */
     public function action_default()
     {
-        $this->output->set_object('task_navigation', $this->menu());
-//        $this->output->set_object('content', 'settings', true);
-
         $caps_actions = $this->get_capability('actions');
+
+        // Display user info by default
         if (self::can_edit_self($caps_actions)) {
             $this->action_info();
         }
+        // otherwise display object types list
+        else if (self::can_edit_types($caps_actions)) {
+            $this->output->set_object('content', 'type', true);
+            $this->action_type_list();
+            unset($this->menu['type_list']);
+
+            // ... and type add form
+            if (!empty($caps_actions['type.add'])) {
+                $this->action_type_add();
+            }
+            else {
+                $this->output->command('set_watermark', 'taskcontent');
+            }
+        }
+        // fallback
         else {
             $this->output->command('set_watermark', 'content');
         }
+
+        $this->output->set_object('task_navigation', $this->menu());
     }
 
     /**
      * Checks if it's possible to edit data of current user
      */
-    public static function can_edit_self($caps_actions)
+    private static function can_edit_self($caps_actions)
     {
         // Disable user form for directory manager (see #1025)
         if (preg_match('/^cn=([a-z ]+)/i', $_SESSION['user']['id'])) {
@@ -69,6 +89,20 @@ class kolab_client_task_settings extends kolab_client_task
     }
 
     /**
+     * Checks if it's possible to edit object types
+     */
+    private static function can_edit_types($caps_actions)
+    {
+        // I think type management interface shouldn't be displayed at all
+        // if user has no write rights to 'type' service
+        if (!empty($caps_actions['type.edit']) || !empty($caps_actions['type.add']) || !empty($caps_actions['type.delete'])) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Check if any of task actions is accessible for current user
      *
      * @return bool
@@ -80,7 +114,7 @@ class kolab_client_task_settings extends kolab_client_task
             return true;
         }
 
-        if (!empty($caps_actions['types.list'])) {
+        if (self::can_edit_types($caps_actions)) {
             return true;
         }
 
@@ -98,18 +132,13 @@ class kolab_client_task_settings extends kolab_client_task
         $menu = array();
 
         foreach ($this->menu as $idx => $label) {
-            if (!array_key_exists($idx, (array)$caps['actions'])) {
+            if (strpos($idx, '.') && !array_key_exists($idx, (array)$caps['actions'])) {
                 continue;
             }
 
-            if (strpos($idx, '.')) {
-                $action = $idx;
-                $class  = preg_replace('/\.[a-z_-]+$/', '', $idx);
-            }
-            else {
-                $action = $task . '.' . $idx;
-                $class  = $idx;
-            }
+            $idx    = str_replace('.', '_', $idx);
+            $action = 'settings.' . $idx;
+            $class  = $idx;
 
             $menu[$idx] = sprintf('<li class="%s">'
                 .'<a href="#%s" onclick="return kadm.command(\'%s\', \'\', this)">%s</a></li>',
@@ -125,7 +154,7 @@ class kolab_client_task_settings extends kolab_client_task
     public function action_info()
     {
         $_POST['id'] = $_SESSION['user']['id'];
-        $user_task    = new kolab_client_task_user($this->output);
+        $user_task   = new kolab_client_task_user($this->output);
         $user_task->action_info();
 
         $this->output->set_object('content', $this->output->get_object('taskcontent'));
@@ -134,7 +163,7 @@ class kolab_client_task_settings extends kolab_client_task
     /**
      * Groups list action.
      */
-    public function action_types_list()
+    public function action_type_list()
     {
         $page_size = 20;
         $page      = (int) self::get_input('page', 'POST');
@@ -144,9 +173,9 @@ class kolab_client_task_settings extends kolab_client_task
 
         // request parameters
         $post = array(
-            'attributes' => array('cn'),
+            'attributes' => array('name', 'key'),
 //            'sort_order' => 'ASC',
-            'sort_by'    => 'cn',
+            'sort_by'    => array('name', 'key'),
             'page_size'  => $page_size,
             'page'       => $page,
         );
@@ -174,15 +203,33 @@ class kolab_client_task_settings extends kolab_client_task
             $post['search_operator'] = 'OR';
         }
 
-        // get groups list
-        $result = $this->api->post('types.list', null, $post);
-        $count  = (int) $result->get('count');
-        $result = (array) $result->get('list');
+        // object type
+        $type = self::get_input('type', 'POST');
+        if (empty($type) || !in_array($type, $this->object_types)) {
+            $type = 'user';
+        }
+
+        // get object types list
+        $result = $this->object_types($type);
+
+        // assign ID
+        foreach (array_keys($result) as $idx) {
+            $result[$idx]['id'] = $idx;
+        }
+
+        $result = array_values($result);
+        $count  = count($result);
 
         // calculate records
         if ($count) {
             $start = 1 + max(0, $page - 1) * $page_size;
             $end   = min($start + $page_size - 1, $count);
+
+            // sort and slice the result array
+
+            if ($count > $page_size) {
+                $result = array_slice($result, $start - 1, $page_size);
+            }
         }
 
         $rows = $head = $foot = array();
@@ -199,16 +246,16 @@ class kolab_client_task_settings extends kolab_client_task
             $next  = $page < $pages ? $page + 1 : 0;
 
             $count_str = kolab_html::span(array(
-                'content' => $this->translate('type.list.records', $start, $end, $count)), true);
+                'content' => $this->translate('list.records', $start, $end, $count)), true);
             $prev = kolab_html::a(array(
                 'class' => 'prev' . ($prev ? '' : ' disabled'),
                 'href'  => '#',
-                'onclick' => $prev ? "kadm.command('type.list', {page: $prev})" : "return false",
+                'onclick' => $prev ? "kadm.command('settings.type_list', {page: $prev})" : "return false",
             ));
             $next = kolab_html::a(array(
                 'class' => 'next' . ($next ? '' : ' disabled'),
                 'href'  => '#',
-                'onclick' => $next ? "kadm.command('type.list', {page: $next})" : "return false",
+                'onclick' => $next ? "kadm.command('settings.type_list', {page: $next})" : "return false",
             ));
 
             $foot_body = kolab_html::span(array('content' => $prev . $count_str . $next));
@@ -218,14 +265,14 @@ class kolab_client_task_settings extends kolab_client_task
         // table body
         if (!empty($result)) {
             foreach ($result as $idx => $item) {
-                if (!is_array($item) || empty($item['cn'])) {
+                if (!is_array($item) || empty($item['name'])) {
                     continue;
                 }
 
                 $i++;
                 $cells = array();
-                $cells[] = array('class' => 'name', 'body' => kolab_html::escape($item['cn']),
-                    'onclick' => "kadm.command('type.info', '$idx')");
+                $cells[] = array('class' => 'name', 'body' => kolab_html::escape($item['name']),
+                    'onclick' => "kadm.command('settings.type_info', '$type:" . $item['id'] . "')");
                 $rows[] = array('id' => $i, 'class' => 'selectable', 'cells' => $cells);
             }
         }
@@ -243,6 +290,7 @@ class kolab_client_task_settings extends kolab_client_task
             'foot'  => $foot,
         ));
 
+        $this->output->command('set_watermark', 'taskcontent');
         $this->output->set_env('search_request', $search_request ? base64_encode(serialize($search_request)) : null);
         $this->output->set_env('list_page', $page);
         $this->output->set_env('list_count', $count);
@@ -254,10 +302,27 @@ class kolab_client_task_settings extends kolab_client_task
      */
     public function action_type_info()
     {
-        $id     = $this->get_input('id', 'POST');
-        $result = $this->api->get('type.info', array('type' => $id));
-        $type   = $result->get();
-        $output = $this->group_form(null, $type);
+        $id   = $this->get_input('id', 'POST');
+        $data = array();
+
+        list($type, $idx) = explode(':', $id);
+
+        if ($idx && $type && ($result = $this->object_types($type))) {
+            if (!empty($result[$idx])) {
+                $data = $result[$idx];
+            }
+        }
+
+        // prepare data for form
+        if (!empty($data)) {
+            $data['id']   = $idx;
+            $data['type'] = $type;
+
+            $data['objectclass'] = $data['attributes']['fields']['objectclass'];
+            unset($data['attributes']['fields']['objectclass']);
+        }
+
+        $output = $this->type_form(null, $data);
 
         $this->output->set_object('taskcontent', $output);
     }
@@ -267,7 +332,15 @@ class kolab_client_task_settings extends kolab_client_task
      */
     public function action_type_add()
     {
-        $data   = $this->get_input('data', 'POST');
+        $data = $this->get_input('data', 'POST');
+
+        if (empty($data['type'])) {
+            $data['type'] = self::get_input('type', 'POST');
+            if (empty($data['type']) || !in_array($data['type'], $this->object_types)) {
+                $data['type'] = 'user';
+            }
+        }
+
         $output = $this->type_form(null, $data, true);
 
         $this->output->set_object('taskcontent', $output);
@@ -290,40 +363,239 @@ class kolab_client_task_settings extends kolab_client_task
 
         // field-to-section map and fields order
         $fields_map = array(
-            'type_id'       => 'props',
-            'objectclasses' => 'props',
-            'type_id_name'  => 'attribs',
+            'id'            => 'props',
+            'type'          => 'props',
+            'key'           => 'props',
+            'name'          => 'props',
+            'description'   => 'props',
+            'objectclass'   => 'props',
+            'used_for'      => 'props',
+            'attributes'    => 'attribs',
         );
 
         // Prepare fields
-        list($fields, $types, $type) = $this->form_prepare('type', $data);
-
+        $fields   = $this->type_form_prepare($data);
         $add_mode = empty($data['id']);
+        $title    = $add_mode ? $this->translate('type.add') : $data['name'];
+
+        // unset $data for correct form_create() run, we've got already data specified
+        $data = array();
+        // enable delete button
+        $data['effective_rights']['entry'] = array('delete');
+
+        // Create form object and populate with fields
+        $form = $this->form_create('type', $attribs, $sections, $fields, $fields_map, $data, $add_mode);
 
-        // Add type id selector
-        $fields['type_id'] = array(
-            'section'  => 'props',
-            'type'     => kolab_form::INPUT_HIDDEN,
+        $form->set_title(kolab_html::escape($title));
+
+        return $form->output();
+    }
+
+    /**
+     * HTML Form elements preparation.
+     *
+     * @param array $data Object data
+     *
+     * @return array Fields list
+     */
+    protected function type_form_prepare(&$data)
+    {
+        // select top class by default for new type
+        if (empty($data['objectclass'])) {
+            $data['objectclass'] = array('top');
+        }
+
+        $name     = 'type';
+        $add_mode = empty($data['id']);
+        $fields   = array(
+            'key' => array(
+                'type' => kolab_form::INPUT_TEXT,
+                'required' => true,
+                'value' => $data['key'],
+            ),
+            'name' => array(
+                'type' => kolab_form::INPUT_TEXT,
+                'required' => true,
+                'value' => $data['name'],
+            ),
+            'description' => array(
+                'type'  => kolab_form::INPUT_TEXTAREA,
+                'value' => $data['description'],
+            ),
+            'objectclass' => array(
+                'type'     => kolab_form::INPUT_SELECT,
+                'name'     => 'objectclass', // needed for form_element_select_data() below
+                'multiple' => true,
+                'required' => true,
+                'value'    => $data['objectclass'],
+            ),
+            'used_for' => array(
+                'value'   => 'hosted',
+                'type'    => kolab_form::INPUT_CHECKBOX,
+                'checked' => !empty($data['used_for']) && $data['used_for'] == 'hosted',
+            ),
+            'attributes' => array(
+                'type'    => kolab_form::INPUT_CONTENT,
+                'content' => $this->type_form_attributes($data),
+            ),
         );
 
-        // Create mode
-        if ($add_mode) {
-            // Page title
-            $title = $this->translate('type.add');
+        if ($data['type'] != 'user') {
+            unset($form_fields['used_for']);
         }
-        // Edit mode
-        else {
-            $title = $data['cn'];
+
+/*
+        // Get the rights on the entry and attribute level
+        $data['effective_rights'] = $this->effective_rights($name, $data['id']);
+        $attribute_rights         = $data['effective_rights']['attribute'];
+        $entry_rights             = $data['effective_rights']['entry'];
+
+        // See if "administrators" (those who can delete and add back on the entry
+        // level) may override the automatically generated contents of auto_form_fields.
+        $admin_auto_fields_rw = $this->config_get('admin_auto_fields_rw', false, Conf::BOOL);
+
+        foreach ($fields as $idx => $field) {
+            if (!array_key_exists($idx, $attribute_rights)) {
+                // If the entry level rights contain 'add' and 'delete', well, you're an admin
+                if (in_array('add', $entry_rights) && in_array('delete', $entry_rights)) {
+                    if ($admin_auto_fields_rw) {
+                        $fields[$idx]['readonly'] = false;
+                    }
+                }
+                else {
+                    $fields[$idx]['readonly'] = true;
+                }
+            }
+            else {
+                if (in_array('add', $entry_rights) && in_array('delete', $entry_rights)) {
+                    if ($admin_auto_fields_rw) {
+                        $fields[$idx]['readonly'] = false;
+                    }
+                }
+                // Explicit attribute level rights, check for 'write'
+                elseif (!in_array('write', $attribute_rights[$idx])) {
+                    $fields[$idx]['readonly'] = true;
+                }
+            }
+        }
+*/
+        // (Re-|Pre-)populate auto_form_fields
+        if (!$add_mode) {
+            // Add debug information
+            if ($this->devel_mode) {
+                ksort($data);
+                $debug = kolab_html::escape(print_r($data, true));
+                $debug = preg_replace('/(^Array\n\(|\n*\)$|\t)/', '', $debug);
+                $debug = str_replace("\n    ", "\n", $debug);
+                $debug = '<pre class="debug">' . $debug . '</pre>';
+                $fields['debug'] = array(
+                    'label'   => 'debug',
+                    'section' => 'props',
+                    'value'   => $debug,
+                );
+            }
         }
 
-        // Create form object and populate with fields
-        $form = $this->form_create('type', $attribs, $sections, $fields, $fields_map, $data, $add_mode);
+        // Get object classes
+        $sd = $this->form_element_select_data($fields['objectclass']);
+        $fields['objectclass'] = array_merge($fields['objectclass'], $sd);
 
-        $form->set_title(kolab_html::escape($title));
+        // Add entry identifier
+        if (!$add_mode) {
+            $fields['id'] = array(
+                'section'   => 'props',
+                'type'      => kolab_form::INPUT_HIDDEN,
+                'value'     => $data['id'],
+            );
+        }
 
-        $this->output->add_translation('type.add.success', 'type.edit.success', 'type.delete.success');
+        $fields['type'] = array(
+            'section'   => 'props',
+            'type'      => kolab_form::INPUT_HIDDEN,
+            'value'     => $data['type'] ?: 'user',
+        );
 
-        return $form->output();
+        return $fields;
+    }
+
+    private function type_form_attributes($data)
+    {
+        $attributes = array();
+        $rows       = array();
+        $table      = array(
+            'class' => 'list',
+        );
+        $cells      = array(
+            'name' => array(
+                'class' => 'name',
+                'body'  => $this->translate('attribute.name'),
+            ),
+            'type' => array(
+                'class' => 'type',
+                'body'  => $this->translate('attribute.type'),
+            ),
+            'optional' => array(
+                'class' => 'optional',
+                'body'  => $this->translate('attribute.optional'),
+            ),
+            'auto' => array(
+                'class' => 'auto',
+                'body'  => $this->translate('attribute.auto'),
+            ),
+            'static' => array(
+                'class' => 'default',
+                'body'  => $this->translate('attribute.static'),
+            ),
+//            'actions' => array(
+//                'class' => 'actions',
+//            ),
+        );
+
+        // get attributes list from $data
+        if (!empty($data) && count($data) > 1) {
+            $attributes = array_merge(
+                array_keys((array) $data['attributes']['auto_form_fields']),
+                array_keys((array) $data['attributes']['form_fields']),
+                array_keys((array) $data['attributes']['fields'])
+            );
+            $attributes = array_filter($attributes);
+            $attributes = array_unique($attributes);
+        }
+
+        // table header
+        $table['head'] = array(array('cells' => $cells));
+/*
+        // attribute row elements
+        $cells['type']['element'] = array(
+            'type'    => kolab_form::INPUT_SELECT,
+            'options' => $this->form_element_types,
+        );
+        $cells['optional']['element'] = array(
+            'type'  => kolab_form::INPUT_CHECKBOX,
+            'value' => 1,
+        );
+*/
+        $yes = $this->translate('yes');
+        // defined attributes
+        foreach ($attributes as $attr) {
+            $row = $cells;
+
+            $type     = $data['attributes']['form_fields'][$attr]['type'];
+            $optional = $data['attributes']['form_fields'][$attr]['optional'];
+
+            // set cell content
+            $row['name']['body']     = $attr;
+            $row['static']['body']   = kolab_html::escape($data['attributes']['fields'][$attr]);
+            $row['auto']['body']     = isset($data['attributes']['fields'][$attr]) ? $yes : '';
+            $row['type']['body']     = !empty($type) ? $type : 'text';
+            $row['optional']['body'] = $optional ? $yes : '';
+
+            $rows[] = array('cells' => $row);
+        }
+
+        $table['body'] = $rows;
+
+        return kolab_html::table($table);
     }
 
     /**
@@ -331,10 +603,10 @@ class kolab_client_task_settings extends kolab_client_task
      *
      * @return string HTML output of the form
      */
-    public function search_form()
+    public function type_search_form()
     {
         $form = new kolab_form(array('id' => 'search-form'));
-/*
+
         $form->add_section('criteria', kolab_html::escape($this->translate('search.criteria')));
         $form->add_element(array(
             'section' => 'criteria',
@@ -342,8 +614,9 @@ class kolab_client_task_settings extends kolab_client_task
             'name'    => 'field',
             'type'    => kolab_form::INPUT_SELECT,
             'options' => array(
-                'cn'   => kolab_html::escape($this->translate('search.name')),
-                'mail' => kolab_html::escape($this->translate('search.email')),
+                'name'        => kolab_html::escape($this->translate('search.name')),
+                'key'         => kolab_html::escape($this->translate('search.key')),
+                'description' => kolab_html::escape($this->translate('search.description')),
             ),
         ));
         $form->add_element(array(
@@ -357,8 +630,32 @@ class kolab_client_task_settings extends kolab_client_task
                 'prefix' => kolab_html::escape($this->translate('search.prefix')),
             ),
         ));
-*/
+
         return $form->output();
     }
 
+    /**
+     * Users search form.
+     *
+     * @return string HTML output of the form
+     */
+    public function type_filter()
+    {
+        $options = array();
+
+        foreach ($this->object_types as $type) {
+            $options[$type] = $this->translate('type.' . $type);
+        }
+
+        $filter = array(
+            'type'     => kolab_form::INPUT_SELECT,
+            'name'     => 'type',
+            'id'       => 'type_list_filter',
+            'options'  => $options,
+            'value'    => $this->type_selected ? $this->type_selected : 'user',
+            'onchange' => "kadm.command('settings.type_list')",
+        );
+
+        return kolab_form::get_element($filter);
+    }
 }
diff --git a/lib/client/kolab_client_task_user.php b/lib/client/kolab_client_task_user.php
index 73dbcc3..859f29a 100644
--- a/lib/client/kolab_client_task_user.php
+++ b/lib/client/kolab_client_task_user.php
@@ -118,7 +118,7 @@ class kolab_client_task_user extends kolab_client_task
             $next  = $page < $pages ? $page + 1 : 0;
 
             $count_str = kolab_html::span(array(
-                'content' => $this->translate('user.list.records', $start, $end, $count)), true);
+                'content' => $this->translate('list.records', $start, $end, $count)), true);
             $prev = kolab_html::a(array(
                 'class' => 'prev' . ($prev ? '' : ' disabled'),
                 'href'  => '#',
@@ -162,6 +162,7 @@ class kolab_client_task_user extends kolab_client_task
             'foot'  => $foot,
         ));
 
+        $this->output->command('set_watermark', 'taskcontent');
         $this->output->set_env('search_request', $search_request ? base64_encode(serialize($search_request)) : null);
         $this->output->set_env('list_page', $page);
         $this->output->set_env('list_count', $count);
@@ -351,8 +352,7 @@ class kolab_client_task_user extends kolab_client_task
 
         $form->set_title(kolab_html::escape($title));
 
-        $this->output->add_translation('user.password.mismatch',
-            'user.add.success', 'user.edit.success', 'user.delete.success');
+        $this->output->add_translation('user.password.mismatch');
 
         return $form->output();
     }
diff --git a/lib/kolab_client_task.php b/lib/kolab_client_task.php
index b2edadf..f3f0aa0 100644
--- a/lib/kolab_client_task.php
+++ b/lib/kolab_client_task.php
@@ -46,9 +46,11 @@ class kolab_client_task
     protected $menu = array();
     protected $cache = array();
     protected $devel_mode = false;
+    protected $object_types = array('user', 'group', 'role', 'resource', 'domain');
 
     protected static $translation = array();
 
+
     /**
      * Class constructor.
      *
@@ -537,37 +539,39 @@ class kolab_client_task
     }
 
     /**
-     * Returns list of user types.
+     * Returns list of object types.
+     *
+     * @para string  $type     Object type name
+     * @param string $used_for Used_for attribute of object type
      *
      * @return array List of user types
      */
-    protected function user_types($used_for = null)
+    protected function object_types($type, $used_for = null)
     {
-        if (!empty($_SESSION['user_types']) && !$this->devel_mode) {
-            return $_SESSION['user_types'];
+        if (empty($type) || !in_array($type, $this->object_types)) {
+            return array();
         }
 
-        $list   = array();
-        $result = $this->api->post('user_types.list');
-        $_list  = $result->get('list');
+        $cache_idx = $type . '_types' . ($used_for ? ":$used_for" : '');
 
-        if (!empty($used_for)) {
-            foreach ($_list as $user_type_id => $user_type_attrs) {
-                if (array_key_exists('used_for', $user_type_attrs) && $user_type_attrs['used_for'] == $used_for) {
-                    $list[$user_type_id] = $user_type_attrs;
+        if (!array_key_exists($cache_idx, $this->cache)) {
+            $result = $this->api->post($type . '_types.list');
+            $list   = $result->get('list');
+
+            if (!empty($used_for)) {
+                foreach ($list as $type_id => $type_attrs) {
+                    if ($type_attrs['used_for'] != $used_for) {
+                        unset($list[$type_id]);
+                    }
                 }
             }
-        } else {
-            $list = $_list;
-        }
 
-        if (is_array($list) && !$this->devel_mode) {
-            $_SESSION['user_types'] = $list;
-        }
+            $this->cache[$cache_idx] = $list;
 
-        Log::trace("kolab_client_task::user_types() returns: " . var_export($list, true));
+            Log::trace("kolab_client_task::${type}_types() returns: " . var_export($list, true));
+        }
 
-        return $list;
+        return $this->cache[$cache_idx];
     }
 
     /**
@@ -784,6 +788,10 @@ class kolab_client_task
             }
             break;
 
+        case 'checkbox':
+            $result['type'] = kolab_form::INPUT_CHECKBOX;
+            break;
+
         case 'password':
             $result['type'] = kolab_form::INPUT_PASSWORD;
 
@@ -820,6 +828,7 @@ class kolab_client_task
         if (!isset($field['values'])) {
             $data['attributes'] = array($field['name']);
             $resp = $this->api->post('form_value.select_options', null, $data);
+
             unset($data['attributes']);
             $field['values'] = $resp->get($field['name']);
         }
@@ -857,17 +866,13 @@ class kolab_client_task
      */
     protected function form_prepare($name, &$data, $extra_fields = array(), $used_for = null)
     {
-        $types        = (array) $this->{$name . '_types'}($used_for);
-
-        $form_id      = $attribs['id'];
+        $types        = (array) $this->object_types($name, $used_for);
         $add_mode     = empty($data['id']);
-
         $event_fields = array();
         $auto_fields  = array();
         $form_fields  = array();
         $fields       = array();
         $auto_attribs = array();
-
         $extra_fields = array_flip($extra_fields);
 
         // Object type
@@ -1103,11 +1108,6 @@ class kolab_client_task
             if (!$field['section']) {
                 $fields[$idx]['section'] = isset($fields_map[$idx]) ? $fields_map[$idx] : 'other';
                 //console("Assigned field $idx to section " . $fields[$idx]['section']);
-/*
-            } else {
-                $fields[$idx]['section'] = 'other';
-                //console("Assigned field $idx to section " . $fields[$idx]['section']);
-*/
             }
         }
 
@@ -1256,7 +1256,8 @@ class kolab_client_task
         $this->output->set_env('form_id', $attribs['id']);
         $this->output->set_env('assoc_fields', $assoc_fields);
         $this->output->set_env('required_fields', $req_fields);
-        $this->output->add_translation('form.required.empty', 'form.maxcount.exceeded');
+        $this->output->add_translation('form.required.empty', 'form.maxcount.exceeded',
+            $name . '.add.success', $name . '.edit.success', $name . '.delete.success');
 
         return $form;
     }
diff --git a/lib/kolab_html.php b/lib/kolab_html.php
index ca40b85..33bc705 100644
--- a/lib/kolab_html.php
+++ b/lib/kolab_html.php
@@ -198,8 +198,13 @@ class kolab_html
                 if (empty($option['value'])) {
                     $option['value'] = $idx;
                 }
-                if (!empty($attribs['value']) && $attribs['value'] == $option['value']) {
-                    $option['selected'] = true;
+                if (!empty($attribs['value'])) {
+                    if (is_array($attribs['value'])) {
+                        $option['selected'] = in_array($option['value'], $attribs['value']);
+                    }
+                    else if ($attribs['value'] == $option['value']) {
+                        $option['selected'] = true;
+                    }
                 }
                 // make a select really readonly by disabling options
                 else if (!empty($attribs['disabled']) || !empty($attribs['readonly'])) {
diff --git a/lib/locale/en_US.php b/lib/locale/en_US.php
index 4527251..9f5561e 100644
--- a/lib/locale/en_US.php
+++ b/lib/locale/en_US.php
@@ -7,6 +7,12 @@ $LANG['about.support'] = 'Professional support is available from <a href="http:/
 $LANG['about.technology'] = 'Technology';
 $LANG['about.warranty'] = 'It comes with absolutely <b>no warranties</b> and is typically run entirely self supported. You can find help & information on the community <a href="http://kolab.org">web site</a> & <a href="http://wiki.kolab.org">wiki</a>.';
 
+$LANG['attribute.auto'] = 'Auto-generated';
+$LANG['attribute.static'] = 'Static value';
+$LANG['attribute.name'] = 'Attribute';
+$LANG['attribute.optional'] = 'Optional';
+$LANG['attribute.type'] = 'Field type';
+
 $LANG['creatorsname'] = 'Created by';
 $LANG['days'] = 'days';
 $LANG['debug'] = 'Debug info';
@@ -20,7 +26,6 @@ $LANG['domain.edit'] = 'Edit domain';
 $LANG['domain.edit.success'] = 'Domain updated';
 $LANG['domain.inetdomainbasedn'] = 'Custom Root DN(s)';
 $LANG['domain.list'] = 'Domains List';
-$LANG['domain.list.records'] = '$1 to $2 of $3';
 $LANG['domain.o'] = 'Organization';
 $LANG['domain.other'] = 'Other';
 $LANG['domain.system'] = 'System';
@@ -38,7 +43,6 @@ $LANG['group.delete.success'] = 'Group deleted successfully.';
 $LANG['group.edit.success'] = 'Group edited successfully.';
 $LANG['group.gidnumber'] = 'Primary group number';
 $LANG['group.list'] = 'Groups List';
-$LANG['group.list.records'] = '$1 to $2 of $3';
 $LANG['group.mail'] = 'Primary Email Address';
 $LANG['group.member'] = 'Member(s)';
 $LANG['group.norecords'] = 'No group records found!';
@@ -49,6 +53,9 @@ $LANG['group.uniquemember'] = 'Members';
 
 $LANG['info'] = 'Information';
 $LANG['internalerror'] = 'Internal system error!';
+
+$LANG['list.records'] = '$1 to $2 of $3';
+
 $LANG['loading'] = 'Loading...';
 $LANG['login.username'] = 'Username:';
 $LANG['login.password'] = 'Password:';
@@ -78,7 +85,6 @@ $LANG['resource.edit'] = 'Edit Resource';
 $LANG['resource.edit.success'] = 'Successfully updated Resource';
 $LANG['resource.kolabtargetfolder'] = 'Target Folder';
 $LANG['resource.list'] = 'Resource (Collection) List';
-$LANG['resource.list.records'] = '$1 to $2 of $3';
 $LANG['resource.mail'] = 'Mail Address';
 $LANG['resource.member'] = 'Collection Members';
 $LANG['resource.norecords'] = 'No resource record(s) found!';
@@ -92,7 +98,6 @@ $LANG['role.cn'] = 'Role Name';
 $LANG['role.description'] = 'Role Description';
 $LANG['role.edit.success'] = 'Role edited successfully';
 $LANG['role.list'] = 'Role List';
-$LANG['role.list.records'] = '$1 to $2 of $3';
 $LANG['role.norecords'] = 'No role records found!';
 $LANG['role.system'] = 'Details';
 $LANG['role.type_id'] = 'Role Type';
@@ -100,15 +105,17 @@ $LANG['role.type_id'] = 'Role Type';
 $LANG['saving'] = 'Saving data...';
 
 $LANG['search'] = 'Search';
-$LANG['search.criteria'] = 'Search criteria';
 $LANG['search.reset'] = 'Reset';
+$LANG['search.criteria'] = 'Search criteria';
 $LANG['search.field'] = 'Field:';
 $LANG['search.method'] = 'Method:';
 $LANG['search.contains'] = 'contains';
 $LANG['search.is'] = 'is';
+$LANG['search.key'] = 'key';
 $LANG['search.prefix'] = 'begins with';
 $LANG['search.name'] = 'name';
 $LANG['search.email'] = 'email';
+$LANG['search.description'] = 'description';
 $LANG['search.uid'] = 'UID';
 $LANG['search.loading'] = 'Searching...';
 $LANG['search.acchars'] = 'At least $min characters required for autocompletion';
@@ -135,6 +142,23 @@ $LANG['signup.footer'] = 'This is a service offered by <a href="http://kolabsys.
 
 $LANG['submit.button'] = 'Submit';
 
+$LANG['type.add'] = 'Add Object Type';
+$LANG['type.attributes'] = 'Attributes';
+$LANG['type.description'] = 'Description';
+$LANG['type.domain'] = 'Domain';
+$LANG['type.group'] = 'Group';
+$LANG['type.list'] = 'Object Types List';
+$LANG['type.key'] = 'Key';
+$LANG['type.name'] = 'Name';
+$LANG['type.norecords'] = 'No object type records found!';
+$LANG['type.objectclass'] = 'Object class';
+$LANG['type.object_type'] = 'Object type';
+$LANG['type.properties'] = 'Properties';
+$LANG['type.resource'] = 'Resource';
+$LANG['type.role'] = 'Role';
+$LANG['type.used_for'] = 'Hosted';
+$LANG['type.user'] = 'User';
+
 $LANG['user.add'] = 'Add User';
 $LANG['user.add.success'] = 'User created successfully.';
 $LANG['user.alias'] = 'Secondary Email Address(es)';
@@ -179,7 +203,6 @@ $LANG['user.kolabhomeserver'] = 'Email Server';
 $LANG['user.kolabinvitationpolicy'] = 'Invitation Handling Policy';
 $LANG['user.l'] = 'City, Region';
 $LANG['user.list'] = 'Users List';
-$LANG['user.list.records'] = '$1 to $2 of $3';
 $LANG['user.loginshell'] = 'Shell';
 $LANG['user.mail'] = 'Primary Email Address';
 $LANG['user.mailalternateaddress'] = 'External Email Address(es)';
diff --git a/public_html/js/kolab_admin.js b/public_html/js/kolab_admin.js
index 2fd8899..c58a592 100644
--- a/public_html/js/kolab_admin.js
+++ b/public_html/js/kolab_admin.js
@@ -1412,7 +1412,7 @@ function kolab_admin()
 
     var page = this.env.list_page;
 
-    // goto previous page if last user on the current page has been deleted
+    // goto previous page if last record on the current page has been deleted
     if (this.env.list_count)
       page -= 1;
 
@@ -1492,7 +1492,7 @@ function kolab_admin()
 
     var page = this.env.list_page;
 
-    // goto previous page if last user on the current page has been deleted
+    // goto previous page if last record on the current page has been deleted
     if (this.env.list_count)
       page -= 1;
 
@@ -1572,7 +1572,7 @@ function kolab_admin()
 
     var page = this.env.list_page;
 
-    // goto previous page if last user on the current page has been deleted
+    // goto previous page if last record on the current page has been deleted
     if (this.env.list_count)
       page -= 1;
 
@@ -1623,6 +1623,105 @@ function kolab_admin()
     this.set_watermark('taskcontent');
   };
 
+  this.settings_type_info = function(id)
+  {
+    this.http_post('settings.type_info', {id: id});
+  };
+
+  this.settings_type_add = function()
+  {
+    this.http_post('settings.type_add', {type: $('#type_list_filter').val()});
+  };
+
+  this.settings_type_list = function(props)
+  {
+    if (!props)
+      props = {};
+
+    if (props.search === undefined && this.env.search_request)
+      props.search_request = this.env.search_request;
+
+    props.type = $('#type_list_filter').val();
+
+    this.http_post('settings.type_list', props);
+  };
+
+  this.type_delete = function(id)
+  {
+    // @TODO:
+    return alert('Not implemented');
+
+    this.set_busy(true, 'deleting');
+    this.api_post('type.delete', this.type_id_parse(id), 'type_delete_response');
+  };
+
+  this.type_delete_response = function(response)
+  {
+    if (!this.api_response(response))
+      return;
+
+    var page = this.env.list_page;
+
+    // goto previous page if last record on the current page has been deleted
+    if (this.env.list_count)
+      page -= 1;
+
+    this.display_message('type.delete.success');
+    this.command('type.list', {page: page});
+    this.set_watermark('taskcontent');
+  };
+
+  this.type_save = function(reload, section)
+  {
+    // @TODO:
+    return alert('Not implemented');
+
+    var data = this.serialize_form('#'+this.env.form_id),
+      action = data.id ? 'edit' : 'add';
+
+    if (reload) {
+      data.section = section;
+      this.http_post('type.' + action, {data: data});
+      return;
+    }
+
+    this.form_error_clear();
+
+    if (!this.check_required_fields(data)) {
+      this.display_message('form.required.empty', 'error');
+      return;
+    }
+
+    this.set_busy(true, 'saving');
+    this.api_post('type.' + action, data, 'type_' + action + '_response');
+  };
+
+  this.type_add_response = function(response)
+  {
+    if (!this.api_response(response))
+      return;
+
+    this.display_message('type.add.success');
+    this.command('settings.type_list', {page: this.env.list_page});
+    this.set_watermark('taskcontent');
+  };
+
+  this.type_edit_response = function(response)
+  {
+    if (!this.api_response(response))
+      return;
+
+    this.display_message('type.edit.success');
+    this.command('settings.type_list', {page: this.env.list_page});
+    this.set_watermark('taskcontent');
+  };
+
+  this.type_id_parse = function(id)
+  {
+    var id = String(id).split(':');
+    return {type: id[0], id: id[1]};
+  };
+
   this.generate_password = function(fieldname)
   {
     this.env.password_field = fieldname;
diff --git a/public_html/skins/default/style.css b/public_html/skins/default/style.css
index 3968c93..9b68183 100644
--- a/public_html/skins/default/style.css
+++ b/public_html/skins/default/style.css
@@ -29,6 +29,10 @@ textarea {
   color: black;
 }
 
+select[multiple="multiple"] {
+  padding-left: 0;
+}
+
 table.list {
   border: 1px solid #d0d0d0;
   border-spacing: 0;
@@ -412,6 +416,12 @@ td.label {
   display: none;
 }
 
+.searchfilter {
+  color: #909090;
+  font-weight: bold;
+  margin-top: 5px;
+}
+
 #search fieldset {
   margin: 0;
   color: #909090;
diff --git a/public_html/skins/default/templates/domain.html b/public_html/skins/default/templates/domain.html
index e658427..1ad4332 100644
--- a/public_html/skins/default/templates/domain.html
+++ b/public_html/skins/default/templates/domain.html
@@ -2,7 +2,7 @@
     <div id="search">
         <div class="searchinput">
             <input type="text" id="searchinput" name="search" value="{$engine->translate('search')}" />
-            <script type="text/javascript">search_init('domain')</script>
+            <script type="text/javascript">search_init('domain.list')</script>
             <span class="searchactions">
                 <span id="search-details" title="{$engine->translate('search.criteria')}" onclick="search_details()"></span>
                 <span id="search-reset" title="{$engine->translate('search.reset')}" onclick="search_reset()"></span>
diff --git a/public_html/skins/default/templates/group.html b/public_html/skins/default/templates/group.html
index 0360bec..e1a4c82 100644
--- a/public_html/skins/default/templates/group.html
+++ b/public_html/skins/default/templates/group.html
@@ -2,7 +2,7 @@
     <div id="search">
         <div class="searchinput">
             <input type="text" id="searchinput" name="search" value="{$engine->translate('search')}" />
-            <script type="text/javascript">search_init('group')</script>
+            <script type="text/javascript">search_init('group.list')</script>
             <span class="searchactions">
                 <span id="search-details" title="{$engine->translate('search.criteria')}" onclick="search_details()"></span>
                 <span id="search-reset" title="{$engine->translate('search.reset')}" onclick="search_reset()"></span>
diff --git a/public_html/skins/default/templates/resource.html b/public_html/skins/default/templates/resource.html
index b2adf2f..0f09c04 100644
--- a/public_html/skins/default/templates/resource.html
+++ b/public_html/skins/default/templates/resource.html
@@ -2,7 +2,7 @@
     <div id="search">
         <div class="searchinput">
             <input type="text" id="searchinput" name="search" value="{$engine->translate('search')}" />
-            <script type="text/javascript">search_init('resource')</script>
+            <script type="text/javascript">search_init('resource.list')</script>
             <span class="searchactions">
                 <span id="search-details" title="{$engine->translate('search.criteria')}" onclick="search_details()"></span>
                 <span id="search-reset" title="{$engine->translate('search.reset')}" onclick="search_reset()"></span>
diff --git a/public_html/skins/default/templates/role.html b/public_html/skins/default/templates/role.html
index ba8d87e..1a37852 100644
--- a/public_html/skins/default/templates/role.html
+++ b/public_html/skins/default/templates/role.html
@@ -2,7 +2,7 @@
     <div id="search">
         <div class="searchinput">
             <input type="text" id="searchinput" name="search" value="{$engine->translate('search')}" />
-            <script type="text/javascript">search_init('role')</script>
+            <script type="text/javascript">search_init('role.list')</script>
             <span class="searchactions">
                 <span id="search-details" title="{$engine->translate('search.criteria')}" onclick="search_details()"></span>
                 <span id="search-reset" title="{$engine->translate('search.reset')}" onclick="search_reset()"></span>
diff --git a/public_html/skins/default/templates/type.html b/public_html/skins/default/templates/type.html
new file mode 100644
index 0000000..8e15792
--- /dev/null
+++ b/public_html/skins/default/templates/type.html
@@ -0,0 +1,18 @@
+<div id="toc" class="type">
+    <div id="search">
+        <div class="searchinput">
+            <input type="text" id="searchinput" name="search" value="{$engine->translate('search')}" />
+            <script type="text/javascript">search_init('settings.type_list')</script>
+            <span class="searchactions">
+                <span id="search-details" title="{$engine->translate('search.criteria')}" onclick="search_details()"></span>
+                <span id="search-reset" title="{$engine->translate('search.reset')}" onclick="search_reset()"></span>
+            </span>
+        </div>
+        <div class="searchdetails">{$engine->type_search_form()}</div>
+        <div class="searchfilter">{$engine->translate('type.object_type')}: {$engine->type_filter()}</div>
+    </div>
+    <div id="typelist"></div>
+</div>
+<div class="vsplitter"> </div>
+<div id="taskcontent" class="type"></div>
+<div class="clear"></div>
diff --git a/public_html/skins/default/templates/user.html b/public_html/skins/default/templates/user.html
index 1c5e732..8244305 100644
--- a/public_html/skins/default/templates/user.html
+++ b/public_html/skins/default/templates/user.html
@@ -2,7 +2,7 @@
     <div id="search">
         <div class="searchinput">
             <input type="text" id="searchinput" name="search" value="{$engine->translate('search')}" />
-            <script type="text/javascript">search_init('user')</script>
+            <script type="text/javascript">search_init('user.list')</script>
             <span class="searchactions">
                 <span id="search-details" title="{$engine->translate('search.criteria')}" onclick="search_details()"></span>
                 <span id="search-reset" title="{$engine->translate('search.reset')}" onclick="search_reset()"></span>
diff --git a/public_html/skins/default/ui.js b/public_html/skins/default/ui.js
index 94891c6..9332051 100644
--- a/public_html/skins/default/ui.js
+++ b/public_html/skins/default/ui.js
@@ -24,9 +24,9 @@
 /**
  * Search form events
  */
-function search_init(task)
+function search_init(command)
 {
-  kadm.env.search_task = task;
+  kadm.env.search_command = command;
 
   $('#searchinput').addClass('inactive')
     .blur(function() {
@@ -38,7 +38,7 @@ function search_init(task)
         var props = kadm.serialize_form('#search-form');
         props.search = this.value;
 
-        kadm.command(kadm.env.search_task + '.list', props);
+        kadm.command(kadm.env.search_command, props);
       }
     })
     .focus(function() {
@@ -53,7 +53,7 @@ function search_reset()
 
   input.val(kadm.t('search')).addClass('inactive');
 
-  kadm.command(kadm.env.search_task + '.list', {search: ''});
+  kadm.command(kadm.env.search_command, {search: ''});
 };
 
 function search_details()


commit 85c4d87227e79350aefd598be5c7a23955be6c4a
Author: Aleksander Machniak <alec at alec.pl>
Date:   Tue Sep 25 14:58:27 2012 +0200

    Make get_element() static and public

diff --git a/lib/kolab_form.php b/lib/kolab_form.php
index ff19098..353d993 100644
--- a/lib/kolab_form.php
+++ b/lib/kolab_form.php
@@ -136,7 +136,7 @@ class kolab_form
                     }
 
                     if ($element['type'] == self::INPUT_HIDDEN) {
-                        $hidden[] = $this->get_element($element);
+                        $hidden[] = self::get_element($element);
                         continue;
                     }
 
@@ -161,7 +161,7 @@ class kolab_form
             }
 
             if ($element['type'] == self::INPUT_HIDDEN) {
-                $hidden[] = $this->get_element($element);
+                $hidden[] = self::get_element($element);
                 continue;
             }
 
@@ -238,7 +238,7 @@ class kolab_form
                 ),
                 1 => array(
                     'class' => 'value',
-                    'body'  => $this->get_element($element),
+                    'body'  => self::get_element($element),
                 ),
             );
         }
@@ -249,7 +249,7 @@ class kolab_form
     /**
      * Builds an element of the form.
      */
-    private function get_element($attribs)
+    public static function get_element($attribs)
     {
         $type = isset($attribs['type']) ? $attribs['type'] : 0;
 


commit b0a4de948fe27fd3dbaf06ed5f0196b0bd6d8f2a
Author: Aleksander Machniak <alec at alec.pl>
Date:   Tue Sep 25 09:33:11 2012 +0200

    Implemented INPUT_CHECKBOX and INPUT_CONTENT

diff --git a/lib/kolab_form.php b/lib/kolab_form.php
index de39bc3..ff19098 100644
--- a/lib/kolab_form.php
+++ b/lib/kolab_form.php
@@ -27,16 +27,17 @@
  */
 class kolab_form
 {
-    const INPUT_TEXT = 1;
+    const INPUT_TEXT     = 1;
     const INPUT_PASSWORD = 2;
     const INPUT_TEXTAREA = 3;
     const INPUT_CHECKBOX = 4;
-    const INPUT_RADIO = 5;
-    const INPUT_BUTTON = 6;
-    const INPUT_SUBMIT = 7;
-    const INPUT_SELECT = 8;
-    const INPUT_HIDDEN = 9;
-    const INPUT_CUSTOM = 10;
+    const INPUT_RADIO    = 5;
+    const INPUT_BUTTON   = 6;
+    const INPUT_SUBMIT   = 7;
+    const INPUT_SELECT   = 8;
+    const INPUT_HIDDEN   = 9;
+    const INPUT_CUSTOM   = 10;
+    const INPUT_CONTENT  = 20;
 
     const TYPE_LIST = 1;
 
@@ -214,23 +215,34 @@ class kolab_form
      */
     private function form_row($element)
     {
-        $cells = array(
-            0 => array(
-                'class' => 'label',
-                'body' => $element['label'],
-            ),
-            1 => array(
-                'class' => 'value',
-                'body' => $this->get_element($element),
-            ),
-        );
-
-        $attrib = array('cells' => $cells);
+        $attrib = array();
 
         if (!empty($element['required']) && empty($element['readonly']) && empty($element['disabled'])) {
             $attrib['class'] = 'required';
         }
 
+        if ($element['type'] == self::INPUT_CONTENT) {
+            $attrib['cells'] = array(
+                0 => array(
+                    'class'   => $element['class'],
+                    'colspan' => 2,
+                    'body'    => $element['content'],
+                ),
+            );
+        }
+        else {
+            $attrib['cells'] = array(
+                0 => array(
+                    'class' => 'label',
+                    'body'  => $element['label'],
+                ),
+                1 => array(
+                    'class' => 'value',
+                    'body'  => $this->get_element($element),
+                ),
+            );
+        }
+
         return $attrib;
     }
 
@@ -265,6 +277,11 @@ class kolab_form
             $content = kolab_html::input($attribs);
             break;
 
+        case self::INPUT_CHECKBOX:
+            $attribs['type'] = 'checkbox';
+            $content = kolab_html::input($attribs);
+            break;
+
         case self::INPUT_HIDDEN:
             $attribs['type'] = 'hidden';
             $content = kolab_html::input($attribs);





More information about the commits mailing list