Convert gollem to new preferences UI code
authorMichael M Slusarz <slusarz@curecanti.org>
Wed, 7 Apr 2010 06:49:08 +0000 (00:49 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 7 Apr 2010 06:49:08 +0000 (00:49 -0600)
framework/Core/lib/Horde/Core/Prefs/Ui/Widgets.php
gollem/config/prefs.php.dist
gollem/js/columnselect.js [deleted file]
gollem/lib/Application.php
gollem/templates/prefs/columnselect.html [deleted file]
gollem/templates/prefs/columnselect.inc [deleted file]
horde/js/sourceselect.js
horde/templates/prefs/source.html

index b4a43ee..99f1325 100644 (file)
@@ -30,13 +30,15 @@ class Horde_Core_Prefs_Ui_Widgets
      * Create code needed for source selection.
      *
      * @param Horde_Core_Prefs_Ui $ui  The UI object.
-     * @param array $data              REQUIRED data items:
+     * @param array $data              Data items:
      * <pre>
-     * 'mainlabel'
-     * 'selected'
-     * 'selectlabel'
-     * 'unselected'
-     * 'unselectlabel'
+     * 'mainlabel' - (string) Main label.
+     * 'selectlabel' - (array) Selected label.
+     * 'sourcelabel' - (string) [OPTIONAL] Source selection label.
+     * 'sources' - (array) List of sources - keys are source names. Each
+     *             source is an array with two entries - selected and
+     *             unselected.
+     * 'unselectlabel' - (array) Unselected label.
      * </pre>
      *
      * @return string  HTML UI code.
@@ -44,29 +46,49 @@ class Horde_Core_Prefs_Ui_Widgets
     static public function source($ui, $data = array())
     {
         $t = $GLOBALS['injector']->createInstance('Horde_Template');
-        $t->setOption('gettext', true);
 
         $t->set('mainlabel', $data['mainlabel']);
         $t->set('selectlabel', $data['selectlabel']);
         $t->set('unselectlabel', $data['unselectlabel']);
 
-        $unselected = array();
-        foreach ($data['unselected'] as $key => $val) {
-            $unselected[] = array(
-                'l' => $val,
-                'v' => $key
-            );
+        $sources = array();
+        foreach ($data['sources'] as $key => $val) {
+            $selected = $unselected = array();
+
+            foreach ($data['selected'] as $key2 => $val2) {
+                $selected[] = array(
+                    'l' => $val2,
+                    'v' => $key2
+                );
+            }
+
+            foreach ($data['unselected'] as $key2 => $val2) {
+                $unselected[] = array(
+                    'l' => $val2,
+                    'v' => $key2
+                );
+            }
+
+            $sources[$key] = array($selected, $unselected);
         }
-        $t->set('unselected', $unselected);
-
-        $selected = array();
-        foreach ($data['selected'] as $key => $val) {
-            $selected[] = array(
-                'l' => $val,
-                'v' => $key
-            );
+
+        if (count($sources) == 1) {
+            $val = reset($sources);
+            $t->set('selected', $val[0]);
+            $t->set('unselected', $val[1]);
+        } else {
+            $js = array();
+            foreach ($sources as $key => $val) {
+                $js[] = array(
+                    'selected' => $val[0],
+                    'source' => $key,
+                    'unselected' => $val[1]
+                );
+            }
+            Horde::addInlineScript(array(
+                'HordeSourceSelectPrefs.source_list = ' . Horde_Serialize::serialize($js, Horde_Serialize::JSON, Horde_Nls::getCharset())
+            ));
         }
-        $t->set('selected', $selected);
 
         $t->set('addimg', Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'lhand.png' : 'rhand.png', _("Add source")));
         $t->set('removeimg', Horde::img(isset($GLOBALS['nls']['rtl'][$GLOBALS['language']]) ? 'rhand.png' : 'lhand.png', _("Remove source")));
@@ -145,9 +167,11 @@ class Horde_Core_Prefs_Ui_Widgets
         if (!empty($selected) || !empty($unselected)) {
             $out = Horde_Core_Prefs_Ui_Widgets::source($ui, array(
                   'mainlabel' => _("Choose the order of address books to search when expanding addresses."),
-                  'selected' => $selected,
                   'selectlabel' => _("Selected address books:"),
-                  'unselected' => $unselected,
+                  'sources' => array(array(
+                      'selected' => $selected,
+                      'unselected' => $unselected
+                  )),
                   'unselectlabel' => _("Available address books:")
              ));
 
index 5f6efa2..45248cc 100644 (file)
@@ -9,8 +9,11 @@ $prefGroups['display'] = array(
     'column' => _("User Interface"),
     'label' => _("File Display"),
     'desc' => _("Change your file sorting options."),
-    'members' => array('show_dotfiles', 'sortdirsfirst', 'columnselect',
-                       'sortby', 'sortdir', 'perpage'));
+    'members' => array(
+        'show_dotfiles', 'sortdirsfirst', 'columnselect', 'sortby', 'sortdir',
+        'perpage'
+    )
+);
 
 $prefGroups['settings'] = array(
     'column' => _("User Interface"),
@@ -21,31 +24,23 @@ $prefGroups['settings'] = array(
 // show dotfiles?
 $_prefs['show_dotfiles'] = array(
     'value' => 1,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("Show dotfiles?")
 );
 
 // columns selection widget
 $_prefs['columnselect'] = array(
-    'locked' => false,
     'type' => 'special'
 );
 
 // columns to be displayed
 $_prefs['columns'] = array(
-    'value' => "ftp\ttype\tname\tdownload\tmodified\tsize\tpermission\towner\tgroup",
-    'locked' => false,
-    'shared' => false,
-    'type' => 'implicit'
+    'value' => "ftp\ttype\tname\tdownload\tmodified\tsize\tpermission\towner\tgroup"
 );
 
 // user preferred sorting column
 $_prefs['sortby'] = array(
     'value' => Gollem::SORT_TYPE,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         Gollem::SORT_TYPE => _("File Type"),
@@ -59,8 +54,6 @@ $_prefs['sortby'] = array(
 // user preferred sorting direction
 $_prefs['sortdir'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         Gollem::SORT_ASCEND => _("Ascending"),
@@ -72,8 +65,6 @@ $_prefs['sortdir'] = array(
 // always sort directories before files
 $_prefs['sortdirsfirst'] = array(
     'value' => 0,
-    'locked' => false,
-    'shared' => false,
     'type' => 'checkbox',
     'desc' => _("List folders first?")
 );
@@ -81,8 +72,6 @@ $_prefs['sortdirsfirst'] = array(
 // number of items per page
 $_prefs['perpage'] = array(
     'value' => 20,
-    'locked' => false,
-    'shared' => true,
     'type' => 'number',
     'desc' => _("Items per page")
 );
@@ -90,8 +79,6 @@ $_prefs['perpage'] = array(
 // user preferred recursive deletes
 $_prefs['recursive_deletes'] = array(
     'value' => 'disabled',
-    'locked' => false,
-    'shared' => false,
     'type' => 'enum',
     'enum' => array(
         'disabled' => _("No"),
diff --git a/gollem/js/columnselect.js b/gollem/js/columnselect.js
deleted file mode 100644 (file)
index 12a7bc0..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * Provides the javascript for the gollem column select preferences page.
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- */
-
-var columns = [];
-
-function selectSource()
-{
-    var f = document.prefs;
-    var fieldString = '';
-
-    while (f.unselected_columns.length > 1) {
-        f.unselected_columns.options[f.unselected_columns.length - 1] = null;
-    }
-    while (f.selected_columns.length > 1) {
-        f.selected_columns.options[f.selected_columns.length - 1] = null;
-    }
-
-    if (f.source.selectedIndex < 1) {
-        return;
-    }
-    var source = f.source.selectedIndex - 1;
-
-    var selected = [];
-    var unselected = [];
-    for (var i = 1; i < columns[source].length; i++) {
-        if (columns[source][i][2]) {
-            selected[columns[source][i][3]] = [columns[source][i][1], columns[source][i][0]];
-        } else {
-            unselected[unselected.length] = [columns[source][i][1], columns[source][i][0]];
-        }
-    }
-    for (i = 0; i < selected.length; i++) {
-        f.selected_columns.options[i + 1] = new Option(selected[i][0], selected[i][1]);
-    }
-    for (i = 0; i < unselected.length; i++) {
-        f.unselected_columns.options[i + 1] = new Option(unselected[i][0], unselected[i][1]);
-    }
-}
-
-function deselectHeaders()
-{
-    document.prefs.unselected_columns[0].selected = false;
-    document.prefs.selected_columns[0].selected = false;
-}
-
-function resetHidden()
-{
-    var tmp = '';
-    for (var i = 0; i < columns.length; i++) {
-        if (i > 0) {
-            tmp += '\n';
-        }
-        tmp += columns[i][0];
-        for (var j = 1; j < columns[i].length; j++) {
-            if (columns[i][j][2]) {
-                tmp += '\t' + columns[i][j][0];
-            }
-        }
-    }
-    document.prefs.columns.value = tmp;
-}
-
-function addColumn()
-{
-    var f = document.prefs;
-    var source = f.source.selectedIndex - 1;
-
-    for (i = 1; i < f.unselected_columns.length; i++) {
-        if (f.unselected_columns[i].selected) {
-            for (var j = 1; j < columns[source].length; j++) {
-                if (columns[source][j][0] == f.unselected_columns[i].value) {
-                    columns[source][j][2] = true;
-                }
-            }
-            f.selected_columns[f.selected_columns.length] = new Option(f.unselected_columns[i].text, f.unselected_columns[i].value);
-            f.unselected_columns[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function removeColumn()
-{
-    var f = document.prefs;
-    var source = f.source.selectedIndex - 1;
-
-    for (i = 1; i < f.selected_columns.length; i++) {
-        if (f.selected_columns[i].selected) {
-            for (var j = 1; j < columns[source].length; j++) {
-                if (columns[source][j][0] == f.selected_columns[i].value) {
-                    columns[source][j][2] = false;
-                }
-            }
-            f.unselected_columns[f.unselected_columns.length] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
-            f.selected_columns[i] = null;
-            i--;
-        }
-    }
-
-    resetHidden();
-}
-
-function moveColumnUp()
-{
-    var f = document.prefs;
-    var sel = f.selected_columns.selectedIndex;
-    var source = f.source.selectedIndex - 1;
-
-    if (sel <= 1 || f.selected_columns.length <= 2) return;
-
-    // deselect everything but the first selected item
-    f.selected_columns.selectedIndex = sel;
-    var up = f.selected_columns[sel].value;
-
-    tmp = [];
-    for (i = 1; i < f.selected_columns.length; i++) {
-        tmp[i - 1] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
-    }
-
-    for (i = 0; i < tmp.length; i++) {
-        if (i + 1 == sel - 1) {
-            f.selected_columns[i + 1] = tmp[i + 1];
-        } else if (i + 1 == sel) {
-            f.selected_columns[i + 1] = tmp[i - 1];
-        } else {
-            f.selected_columns[i + 1] = tmp[i];
-        }
-    }
-
-    f.selected_columns.selectedIndex = sel - 1;
-
-    for (i = 2; i < columns[source].length - 1; i++) {
-        if (columns[source][i][0] == up) {
-            column = columns[source][i];
-            columns[source][i] = columns[source][i - 1];
-            columns[source][i - 1] = column;
-        }
-    }
-
-    resetHidden();
-}
-
-function moveColumnDown()
-{
-    var f = document.prefs;
-    var sel = f.selected_columns.selectedIndex;
-    var source = f.source.selectedIndex - 1;
-
-    if (sel == -1 || f.selected_columns.length <= 2 || sel == f.selected_columns.length - 1) return;
-
-    // deselect everything but the first selected item
-    f.selected_columns.selectedIndex = sel;
-    var down = f.selected_columns[sel].value;
-
-    tmp = [];
-    for (i = 1; i < f.selected_columns.length; i++) {
-        tmp[i - 1] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
-    }
-
-    for (i = 0; i < tmp.length; i++) {
-        if (i + 1 == sel) {
-            f.selected_columns[i + 1] = tmp[i + 1];
-        } else if (i + 1 == sel + 1) {
-            f.selected_columns[i + 1] = tmp[i - 1];
-        } else {
-            f.selected_columns[i + 1] = tmp[i];
-        }
-    }
-
-    f.selected_columns.selectedIndex = sel + 1;
-
-    for (i = columns[source].length - 2; i > 0; i--) {
-        if (columns[source][i][0] == down || columns[source][i + 1][0] == down) {
-            column = columns[source][i];
-            columns[source][i] = columns[source][i + 1];
-            columns[source][i + 1] = column;
-        }
-    }
-
-    resetHidden();
-}
index b58f0b3..e7e7c25 100644 (file)
@@ -96,6 +96,70 @@ class Gollem_Application extends Horde_Registry_Application
     }
 
     /**
+     * Code to run on init when viewing prefs for this application.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     */
+    public function prefsInit($ui)
+    {
+        global $prefs;
+
+        switch ($ui->group) {
+        case 'display':
+            if (!$prefs->isLocked('columns')) {
+                Horde_Core_Prefs_Ui_Widgets::sourceInit($ui);
+            }
+            break;
+        }
+    }
+
+    /**
+     * Generate code used to display a special preference.
+     *
+     * @param Horde_Core_Prefs_Ui $ui  The UI object.
+     * @param string $item             The preference name.
+     *
+     * @return string  The HTML code to display on the options page.
+     */
+    public function prefsSpecial($ui, $item)
+    {
+        switch ($item) {
+        case 'columnselect':
+            $cols = Gollem::displayColumns();
+            $sources = array();
+
+            foreach ($GLOBALS['gollem_backends'] as $source => $info) {
+                $selected = $unselected = array();
+                $selected_list = isset($cols[$source])
+                    ? array_flip($cols[$source]) :
+                    : array();
+
+                foreach ($info['attributes'] as $column) {
+                    if (isset($selected_list[$column])) {
+                        $selected[] = array($column, $column);
+                    } else {
+                        $unselected[] = array($column, $column);
+                    }
+                }
+                $sources[$source] = array(
+                    'selected' => $selected,
+                    'unselected' => $unselected,
+                );
+            }
+
+            return Horde_Core_Prefs_Ui_Widgets::source($ui, array(
+                'mainlabel' => _("Choose which address books to display, and in what order:"),
+                'selectlabel' => _("These addressbooks will display in this order:"),
+                'sourcelabel' => _("Select a backend:"),
+                'sources' => $foo,
+                'unselectlabel' => _("Address books that will not be displayed:")
+            ));
+        }
+
+        return '';
+    }
+
+    /**
      * Special preferences handling on update.
      *
      * @param Horde_Core_Prefs_Ui $ui  The UI object.
@@ -107,12 +171,18 @@ class Gollem_Application extends Horde_Registry_Application
     {
         switch ($item) {
         case 'columnselect':
-            if (isset($ui->vars->columns)) {
-                $GLOBALS['prefs']->setValue('columns', $ui->vars->columns);
+            if (isset($ui->vars->sources)) {
+                $pref = array();
+                foreach (Horde_Serialize::unserialize($ui->vars->sources, Horde_Serialize::JSON) as $val) {
+                    $pref[] = implode("\t", array_merge($val[0], $val[1]));
+                }
+                $GLOBALS['prefs']->setValue('columns', implode("\n", $pref));
                 return true;
             }
             break;
         }
+
+        return false;
     }
 
     /**
diff --git a/gollem/templates/prefs/columnselect.html b/gollem/templates/prefs/columnselect.html
deleted file mode 100644 (file)
index 2a86c0d..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<input type="hidden" name="columns" value="<tag:columns />" />
-
-<div>
- <select name="source" onchange="if (document.prefs.source.selectedIndex != 0) selectSource();">
-  <option value=""><gettext>Please select a backend:</gettext></option>
-<loop:be>
-  <option value="<tag:be.val />"><tag:be.label /></option>
-</loop:be>
- </select>
-</div>
-
-<gettext>Choose the columns to display in the file manager.</gettext>
-
-<br />
-
-<table>
- <tr>
-  <td>
-   <select name="unselected_columns" multiple="multiple" size="5" width="20" onchange="deselectHeaders();">
-    <option value=""><gettext>Available Columns:</gettext></option>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="addColumn(); return false;"><tag:add /></a>
-   <br />
-   <a href="#" onclick="removeColumn(); return false;"><tag:remove /></a>
-  </td>
-  <td>
-   <select name="selected_columns" multiple="multiple" size="5" width="20" onchange="deselectHeaders();">
-    <option value=""><gettext>Selected Columns:</gettext></option>
-   </select>
-  </td>
-  <td>
-   <a href="#" onclick="moveColumnUp(); return false;"><tag:left /></a>
-   <br />
-   <a href="#" onclick="moveColumnDown(); return false;"><tag:right /></a>
-  </td>
- </tr>
-</table>
diff --git a/gollem/templates/prefs/columnselect.inc b/gollem/templates/prefs/columnselect.inc
deleted file mode 100644 (file)
index a882f55..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * Horde_Prefs_Ui:: always calls a .inc file, so we need to use this file to
- * generate the data needed to display the template.
- */
-
-if (!$prefs->isLocked('columns')) {
-    $js_columns = '';
-    $sources = Gollem::displayColumns();
-    $source_count = 0;
-
-    foreach ($GLOBALS['gollem_backends'] as $source => $info) {
-        $js_columns .= "columns[$source_count] = [];";
-        $js_columns .= "columns[$source_count][0] = '$source';";
-
-        $column_count = 1;
-        $selected = isset($sources[$source]) ? array_flip($sources[$source]) : array();
-        foreach ($info['attributes'] as $null => $column) {
-            $marked = isset($selected[$column]) ? 'true' : 'false';
-            $js_columns .= "columns[$source_count][$column_count] = ['$column', '" . addslashes($column) . "', $marked, " . (($marked === 'true') ? $selected[$column] : 'null') . "];";
-            ++$column_count;
-        }
-        ++$source_count;
-    }
-
-    Horde::addScriptFile('columnselect.js', 'gollem');
-    Horde::addInlineScript($js_columns);
-
-    $t = $injector->createInstance('Horde_Template');
-    $t->setOption('gettext', true);
-
-    $be = array();
-    foreach ($GLOBALS['gollem_backends'] as $key => $info) {
-        $be[] = array('val' => $key, 'label' => $info['name']);
-    }
-    $t->set('be', $be);
-
-    $t->set('columns', $prefs->getValue('columns'));
-
-    $t->set('add', Horde::img('rhand.png', _("Add column")));
-    $t->set('remove', Horde::img('lhand.png', _("Remove column")));
-    $t->set('left', Horde::img('nav/up.png', _("Move left")));
-    $t->set('right', Horde::img('nav/down.png', _("Move right")));
-
-    echo $t->fetch(GOLLEM_TEMPLATES . '/prefs/columnselect.html');
-}
index 0af423f..b34b958 100644 (file)
@@ -1,15 +1,32 @@
 /**
  * Provides the javascript for managing the source selection widget.
  *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  */
 
 var HordeSourceSelectPrefs = {
 
-    resetHidden: function()
+    // Vars defaulting to null: source_list
+
+    setSourcesHidden: function()
     {
-        $('sources').setValue($F('selected_sources').toJSON());
+        var out = [], ss;
+
+        if (this.source_list) {
+            ss = $F('source_select');
+            if (ss) {
+                this.source_list.each(function(s) {
+                    if (s.source == ss) {
+                        s.selected = $F('selected_sources');
+                    }
+                    out.push([ s.source, s.selected ]);
+                });
+                $('sources').setValue(out.toJSON());
+            }
+        } else {
+            $('sources').setValue($F('selected_sources').toJSON());
+        }
     },
 
     moveAction: function(from, to)
@@ -21,7 +38,7 @@ var HordeSourceSelectPrefs = {
             }
         });
 
-        this.resetHidden();
+        this.setSourcesHidden();
     },
 
     moveSource: function(e, mode)
@@ -59,20 +76,46 @@ var HordeSourceSelectPrefs = {
             break;
         }
 
-        this.resetHidden();
+        this.setSourcesHidden();
         e.stop();
     },
 
-    onDomLoad: function()
+    changeSource: function()
     {
-        this.resetHidden();
+        var source,
+            sel = $('selected_sources'),
+            ss = $('source_select'),
+            unsel = $('unselected_sources'),
+            val = $F(ss);
+
+        sel.down().siblings().invoke('remove');
+        unsel.down().siblings().invoke('remove');
 
-        if ($('unselected_sources')) {
-            $('addsource').observe('click', this.moveAction.bind(this, 'unselected_sources', 'selected_sources'));
-            $('removesource').observe('click', this.moveAction.bind(this, 'selected_sources', 'unselected_sources'));
-            $('moveup').observe('click', this.moveSource.bindAsEventListener(this, 'up'));
-            $('movedown').observe('click', this.moveSource.bindAsEventListener(this, 'down'));
+        if (val) {
+            source = this.source_list.find(function(s) {
+                return val == s.source;
+            });
+            source.selected.each(function(s) {
+                sel.insert(new Option(s.v, s.l));
+            });
+            source.unselected.each(function(u) {
+                unsel.insert(new Option(s.v, s.l));
+            });
         }
+    },
+
+    onDomLoad: function()
+    {
+        if (this.source_list) {
+            $('source_select').observe('change', this.changeSource.bind(this));
+        }
+
+        this.setSourcesHidden();
+
+        $('addsource').observe('click', this.moveAction.bind(this, 'unselected_sources', 'selected_sources'));
+        $('removesource').observe('click', this.moveAction.bind(this, 'selected_sources', 'unselected_sources'));
+        $('moveup').observe('click', this.moveSource.bindAsEventListener(this, 'up'));
+        $('movedown').observe('click', this.moveSource.bindAsEventListener(this, 'down'));
     }
 
 };
index cfa1dbc..4a958a4 100644 (file)
@@ -4,15 +4,25 @@
   <tag:mainlabel />
  </p>
 
+<if:source_select>
+ <div>
+  <select id="source_select" name="source_select">
+   <option value=""><tag:sourcelabel /></option>
+  </select>
+ </div>
+</if:source_select>
+
  <table>
   <tr>
    <td>
     <label for="unselected_sources" class="hidden"><tag:unselectlabel /></label>
     <select id="unselected_sources" name="unselected_sources" multiple="multiple" size="5">
      <option class="control" disabled="disabled" value=""><tag:unselectlabel /></option>
+<if:unselected>
 <loop:unselected>
      <option value="<tag:unselected.v />"><tag:unselected.l /></option>
 </loop:unselected>
+</if:unselected>
     </select>
    </td>
    <td>
     <label for="selected_sources" class="hidden"><tag:selectlabel /></label>
     <select name="selected_sources" multiple="multiple" size="5" id="selected_sources">
      <option class="control" disabled="disabled" value=""><tag:selectlabel /></option>
+<if:selected>
 <loop:selected>
      <option value="<tag:selected.v />"><tag:selected.l /></option>
 </loop:selected>
+</if:selected>
     </select>
    </td>
    <td>