Add vertical-pane preview layout to DIMP.
authorMichael M Slusarz <slusarz@curecanti.org>
Tue, 17 Nov 2009 03:48:11 +0000 (20:48 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 17 Nov 2009 19:25:51 +0000 (12:25 -0700)
Thank you Microsoft Outlook.

imp/docs/CHANGES
imp/js/DimpBase.js
imp/js/ViewPort.js
imp/js/mailbox-dimp.js
imp/templates/index/index-dimp.inc
imp/templates/javascript_defs_dimp.php
imp/themes/graphics/dragHandleVert.png [new file with mode: 0644]
imp/themes/ie6_or_less-dimp.css
imp/themes/ie7-dimp.css
imp/themes/screen-dimp.css

index 3cbc704..31fd1e9 100644 (file)
@@ -2,6 +2,7 @@
 v5.0-git
 --------
 
+[mms] Add vertical-pane preview layout to DIMP.
 [mms] Wrap content-related MIME parts in a border when viewing inline to
       indicate their relationship.
 [mms] For drafts, save the original message index for forwards/replies so when
index 5fdba6c..b17e42a 100644 (file)
@@ -10,8 +10,9 @@
 var DimpBase = {
     // Vars used and defaulting to null/false:
     //   cfolderaction, folder, folderswitch, offset, pollPE, pp, search,
-    //   uid, viewport
-    // message_list_template set via js/mailbox-dimp.js
+    //   template, uid, viewport
+    // msglist_template_horiz and msglist_template_vert set via
+    //   js/mailbox-dimp.js
     cacheids: {},
     lastrow: -1,
     pivotrow: -1,
@@ -390,86 +391,42 @@ var DimpBase = {
 
     _createViewPort: function()
     {
+        [ $('msglistHeader') ].invoke(DIMP.conf.preview_pref == 'vert' ? 'hide' : 'show');
+
+        this.template = {
+            horiz: new Template(this.msglist_template_horiz),
+            vert: new Template(this.msglist_template_vert)
+        };
+
         this.viewport = new ViewPort({
             // Mandatory config
             ajax_url: DIMP.conf.URI_AJAX + '/ViewPort',
-            content: 'msgList',
-            template: this.message_list_template,
-
-            // Optional config
-            ajax_opts: DimpCore.doActionOpts,
-            buffer_pages: DIMP.conf.buffer_pages,
-            content_class: 'msglist',
-            empty_msg: DIMP.text.vp_empty,
-            page_size: DIMP.conf.splitbar_pos,
-            show_split_pane: DIMP.conf.preview_pref,
-            split_bar: 'splitBar',
-            split_pane: 'previewPane',
-            wait: DIMP.conf.viewport_wait,
-
-            // Callbacks
-            onAjaxRequest: function(id) {
-                var p = $H();
-                if (this.folderswitch && this.isSearch(id, true)) {
-                    p.set('qsearchmbox', this.search.mbox);
-                    if (this.search.flag) {
-                        p.update({ qsearchflag: this.search.flag, qsearchflagnot: Number(this.convertFlag(this.search.flag, this.search.not)) });
-                    } else {
-                        p.set('qsearch', $F('qsearch_input'));
-                    }
-                }
-                return DimpCore.addRequestParams(p);
-            }.bind(this),
-            onAjaxResponse: DimpCore.doActionComplete.bind(DimpCore),
-            onCachedList: function(id) {
-                var tmp, vs;
-                if (!this.cacheids[id]) {
-                    vs = this.viewport.getSelection(id);
-                    if (!vs.size()) {
-                        return '';
-                    }
-
-                    if (vs.getBuffer().getMetaData('search')) {
-                        this.cacheids[id] = vs.get('uid').toJSON();
-                    } else {
-                        tmp = {};
-                        tmp[id] = vs.get('uid').clone();
-                        this.cacheids[id] = DimpCore.toRangeString(tmp);
-                    }
-                }
-                return this.cacheids[id];
-            }.bind(this),
-            onCacheUpdate: function(id) {
-                delete this.cacheids[id];
-            }.bind(this),
-            onClear: function(r) {
-                r.each(this._removeMouseEvents.bind(this));
-            }.bind(this),
-            onContent: function(row) {
+            container: 'msgSplitPane',
+            onContent: function(r, mode) {
                 var bg, re, u,
                     thread = $H(this.viewport.getMetaData('thread')),
                     tsort = (this.viewport.getMetaData('sortby') == $H(DIMP.conf.sort).get('thread').v);
 
-                row.subjectdata = row.status = '';
-                row.subjecttitle = row.subject;
+                r.subjectdata = r.status = '';
+                r.subjecttitle = r.subject;
 
                 // Add thread graphics
                 if (tsort) {
-                    u = thread.get(row.imapuid);
+                    u = thread.get(r.imapuid);
                     if (u) {
                         $R(0, u.length, true).each(function(i) {
                             var c = u.charAt(i);
                             if (!this.tcache[c]) {
                                 this.tcache[c] = '<span class="treeImg treeImg' + c + '"></span>';
                             }
-                            row.subjectdata += this.tcache[c];
+                            r.subjectdata += this.tcache[c];
                         }, this);
                     }
                 }
 
                 /* Generate the status flags. */
-                if (row.flag) {
-                    row.flag.each(function(a) {
+                if (r.flag) {
+                    r.flag.each(function(a) {
                         var ptr = DIMP.conf.flags[a];
                         if (ptr.p) {
                             if (!ptr.elt) {
@@ -478,14 +435,14 @@ var DimpBase = {
                                  * ourselves. */
                                 ptr.elt = '<span class="' + ptr.c + '" title="' + ptr.l + '" style="background:' + ptr.b + ';color:' + ptr.f + '">' + ptr.l.truncate(10) + '</span>';
                             }
-                            row.subjectdata += ptr.elt;
+                            r.subjectdata += ptr.elt;
                         } else {
                             if (!ptr.elt) {
                                 ptr.elt = '<div class="msgflags ' + ptr.c + '" title="' + ptr.l + '"></div>';
                             }
-                            row.status += ptr.elt;
+                            r.status += ptr.elt;
 
-                            row.bg.push(ptr.c);
+                            r.bg.push(ptr.c);
 
                             if (ptr.b) {
                                 bg = ptr.b;
@@ -496,26 +453,90 @@ var DimpBase = {
 
                 // Set bg
                 if (bg) {
-                    row.style = 'background:' + bg;
+                    r.style = 'background:' + bg;
                 }
 
                 // Check for search strings
                 if (this.isSearch(null, true)) {
                     re = new RegExp("(" + $F('qsearch_input') + ")", "i");
                     [ 'from', 'subject' ].each(function(h) {
-                        row[h] = row[h].gsub(re, '<span class="qsearchMatch">#{1}</span>');
+                        r[h] = r[h].gsub(re, '<span class="qsearchMatch">#{1}</span>');
                     });
                 }
 
                 // If these fields are null, invalid string was scrubbed by
                 // JSON encode.
-                if (row.from === null) {
-                    row.from = '[' + DIMP.text.badaddr + ']';
+                if (r.from === null) {
+                    r.from = '[' + DIMP.text.badaddr + ']';
                 }
-                if (row.subject === null) {
-                    row.subject = row.subjecttitle = '[' + DIMP.text.badsubject + ']';
+                if (r.subject === null) {
+                    r.subject = r.subjecttitle = '[' + DIMP.text.badsubject + ']';
+                }
+
+                r.bg.push('vpRow');
+
+                switch (mode) {
+                case 'vert':
+                    r.bg.unshift('vpRowVert');
+                    r.className = r.bg.join(' ');
+                    return this.template.vert.evaluate(r);
+
+                default:
+                    r.bg.unshift('vpRowHoriz');
+                    r.className = r.bg.join(' ');
+                    return this.template.horiz.evaluate(r);
                 }
             }.bind(this),
+
+            // Optional config
+            ajax_opts: DimpCore.doActionOpts,
+            buffer_pages: DIMP.conf.buffer_pages,
+            empty_msg: DIMP.text.vp_empty,
+            list_class: 'msglist',
+            page_size: DIMP.conf.splitbar_pos,
+            pane_data: 'previewPane',
+            pane_mode: DIMP.conf.preview_pref,
+            split_bar_class: { horiz: 'splitBarHoriz', vert: 'splitBarVert' },
+            wait: DIMP.conf.viewport_wait,
+
+            // Callbacks
+            onAjaxRequest: function(id) {
+                var p = $H();
+                if (this.folderswitch && this.isSearch(id, true)) {
+                    p.set('qsearchmbox', this.search.mbox);
+                    if (this.search.flag) {
+                        p.update({ qsearchflag: this.search.flag, qsearchflagnot: Number(this.convertFlag(this.search.flag, this.search.not)) });
+                    } else {
+                        p.set('qsearch', $F('qsearch_input'));
+                    }
+                }
+                return DimpCore.addRequestParams(p);
+            }.bind(this),
+            onAjaxResponse: DimpCore.doActionComplete.bind(DimpCore),
+            onCachedList: function(id) {
+                var tmp, vs;
+                if (!this.cacheids[id]) {
+                    vs = this.viewport.getSelection(id);
+                    if (!vs.size()) {
+                        return '';
+                    }
+
+                    if (vs.getBuffer().getMetaData('search')) {
+                        this.cacheids[id] = vs.get('uid').toJSON();
+                    } else {
+                        tmp = {};
+                        tmp[id] = vs.get('uid').clone();
+                        this.cacheids[id] = DimpCore.toRangeString(tmp);
+                    }
+                }
+                return this.cacheids[id];
+            }.bind(this),
+            onCacheUpdate: function(id) {
+                delete this.cacheids[id];
+            }.bind(this),
+            onClear: function(r) {
+                r.each(this._removeMouseEvents.bind(this));
+            }.bind(this),
             onContentComplete: function(rows) {
                 var row, ssc, tmp,
                     l = this.viewport.getMetaData('label');
@@ -615,13 +636,15 @@ var DimpBase = {
             onFetch: this.loadingImg.bind(this, 'viewport', true),
             onSelect: this._select.bind(this),
             onSlide: this.setMessageListTitle.bind(this),
-            onSplitBarChange: function() {
-                this._updatePrefs('dimp_splitbar', this.viewport.getPageSize());
+            onSplitBarChange: function(mode) {
+                if (mode = 'horiz') {
+                    this._updatePrefs('dimp_splitbar', this.viewport.getPageSize());
+                }
             }.bind(this),
-            onSplitBarEnd: function() {
+            onSplitBarEnd: function(mode) {
                 $('messageBodyCover').hide();
             },
-            onSplitBarStart: function() {
+            onSplitBarStart: function(mode) {
                 $('messageBodyCover').clonePosition('messageBody').show();
             },
             onWait: function() {
@@ -765,8 +788,17 @@ var DimpBase = {
             break;
 
         case 'oa_preview_hide':
+            DIMP.conf.preview_pref_old = DIMP.conf.preview_pref;
+            this.togglePreviewPane('');
+            break;
+
         case 'oa_preview_show':
-            this.togglePreviewPane();
+            this.togglePreviewPane(DIMP.conf.preview_pref_old || 'horiz');
+            break;
+
+        case 'oa_layout_horiz':
+        case 'oa_layout_vert':
+            this.togglePreviewPane(id.substring(10));
             break;
 
         case 'oa_blacklist':
@@ -873,12 +905,21 @@ var DimpBase = {
             break;
 
         case 'ctx_otheractions':
-            if (DIMP.conf.preview_pref) {
-                $('oa_preview_hide').show();
-                $('oa_preview_show').hide();
-            } else {
-                $('oa_preview_hide').hide();
+            switch (DIMP.conf.preview_pref) {
+            case 'vert':
+                $('oa_preview_hide', 'oa_layout_horiz').invoke('show');
+                $('oa_preview_show', 'oa_layout_vert').invoke('hide');
+                break;
+
+            case 'horiz':
+                $('oa_preview_hide', 'oa_layout_vert').invoke('show');
+                $('oa_preview_show', 'oa_layout_horiz').invoke('hide');
+                break;
+
+            default:
+                $('oa_preview_hide', 'oa_layout_horiz', 'oa_layout_vert').invoke('hide');
                 $('oa_preview_show').show();
+                break;
             }
             tmp = [ $('oa_undeleted') ];
             $('oa_blacklist', 'oa_whitelist').each(function(o) {
@@ -1022,14 +1063,18 @@ var DimpBase = {
     },
 
     // Preview pane functions
-    togglePreviewPane: function()
+    // mode = (string) Either 'horiz', 'vert', or empty
+    togglePreviewPane: function(mode)
     {
-        var p = DIMP.conf.preview_pref = !DIMP.conf.preview_pref;
-        $('oa_preview_hide', 'oa_preview_show').invoke('toggle');
-        this._updatePrefs('show_preview', Number(p));
-        this.viewport.showSplitPane(p);
-        if (p) {
-            this.initPreviewPane();
+        var old = DIMP.conf.preview_pref;
+        if (mode != DIMP.conf.preview_pref) {
+            DIMP.conf.preview_pref = mode;
+            this._updatePrefs('dimp_show_preview', mode);
+            [ $('msglistHeader') ].invoke(mode == 'vert' ? 'hide' : 'show');
+            this.viewport.showSplitPane(mode);
+            if (!old) {
+                this.initPreviewPane();
+            }
         }
     },
 
@@ -1664,9 +1709,8 @@ var DimpBase = {
             tmp.draft
                 ? DimpCore.compose('resume', { folder: tmp.view, uid: tmp.imapuid })
                 : this.msgWindow(tmp);
+            e.stop();
         }
-
-        e.stop();
     },
 
     clickHandler: function(parentfunc, e)
@@ -2545,7 +2589,7 @@ var DimpBase = {
         var c;
 
         if (show) {
-            $(id + 'Loading').clonePosition(id == 'viewport' ? 'msgList' : 'splitBar', { setLeft: false, setTop: true, setHeight: false, setWidth: false }).show();
+            $(id + 'Loading').clonePosition(id == 'viewport' ? 'msgSplitPane' : 'previewPane', { setLeft: false, setTop: true, setHeight: false, setWidth: false }).show();
             c = 'progress';
         } else {
             $(id + 'Loading').fade({ duration: 0.2 });
@@ -2578,13 +2622,11 @@ var DimpBase = {
         /* Register global handlers now. */
         document.observe('keydown', this.keydownHandler.bindAsEventListener(this));
         document.observe('change', this.changeHandler.bindAsEventListener(this));
+        document.observe('dblclick', this.dblclickHandler.bindAsEventListener(this));
 
         /* Limit to folders sidebar only. */
         $('foldersSidebar').observe('mouseover', this.mouseoverHandler.bindAsEventListener(this));
 
-        /* Limit to msgList only. */
-        $('msgList').observe('dblclick', this.dblclickHandler.bindAsEventListener(this));
-
         /* Show page now. */
         $('sidebarPanel').setStyle({ width: DIMP.conf.sidebar_width });
         $('dimpLoading').hide();
index 55f3784..c45450d 100644 (file)
@@ -1,5 +1,6 @@
 /**
- * ViewPort.js - Code to create a viewport window in a web browser.
+ * ViewPort.js - Code to create a viewport window, with optional split pane
+ * functionality.
  *
  * Usage:
  * ======
  * -----------------
  * ajax_url: (string) The URL to send the viewport requests to.
  *           This URL should return its response in an object named
- *           'ViewPort' (other information can be returned in the response).
- * content: (Element/string) A DOM element/ID of the container to hold the
- *          viewport rows.
- * template: (string) TODO DIV with 'vpData'
- *                    Class: 'vpRow' 'vpRowSelected'
+ *           'ViewPort' (other information can be returned in the response and
+ *           will be ignored by the viewport object).
+ * container: (Element/string) A DOM element/ID of the container that holds
+ *            the viewport. This element should be empty and have no children.
+ * onContent: (function) A function that takes 2 arguments - the data object
+ *            for the row and a string indicating the current pane_mode.
+ *
+ *            This function MUST return the HTML representation of the row.
+ *
+ *            This representation MUST include both the DOM ID (stored in
+ *            the domid field) and the CSS class name (stored as an array in
+ *            the bg field) in the outermost element.
+ *
+ *            Selected rows will contain the classname 'vpRowSelected'.
+ *
  *
  * Optional options:
  * -----------------
  *               within this percentage of the end of the current cached
  *               viewport, send a background request to the server to retrieve
  *               the next slice.
+ * list_class: (string) The CSS class to use for the list container.
  * lookbehind: (integer) What percentage of the received buffer should be
- *             used to download messages before the given row number?
- * page_size: (integer) Default page size to view on load.
- * show_split_pane: (boolean) Show the split pane on load?
- * split_bar: (Element/string) A DOM element/ID of the element used to display
- *            the split bar.
- * split_pane: (Element/string) A DOM element/ID of the container to hold
- *             the split pane info.
+ *             used to download rows before the given row number?
+ * page_size: (integer) Default page size to view on load. Only used if
+ *            pane_mode is 'horiz'.
+ * pane_data: (Element/string) A DOM element/ID of the container to hold
+ *            the split pane data. This element will be moved inside of the
+ *            container element.
+ * pane_mode: (string) The split pane mode to show on load? Either empty,
+ *            'horiz', or 'vert'.
+ * split_bar_class: (object) The CSS class(es) to use for the split bar.
+ *                  Takes two properties: 'horiz' and 'vert'.
  * wait: (integer) How long, in seconds, to wait before displaying an
- *       informational message to users that the message list is still being
+ *       informational message to users that the list is still being
  *       built.
  *
+ *
  * Callbacks:
  * ----------
  * onAjaxRequest
  * onFetch
  * onSelect
  * onSlide
+ *
  * onSplitBarChange
  * onSplitBarEnd
  * onSplitBarStart
+ *   + Passed the current pane mode (either 'horiz' or 'vert').
+ *
  * onWait
  *
+ *
  * Outgoing AJAX request has the following params:
  * -----------------------------------------------
  * For ALL requests:
  *   slice: (string) The list of rows to retrieve from the server.
  *          In the format: [first_row]:[last_row]
  *
+ *
  * Incoming AJAX response has the following params:
  * ------------------------------------------------
  * cacheid: (string) A unique string that changes whenever the viewport
  *                    overwriting it.
  * view: (string) The view ID of the request.
  *
+ *
+ * Scroll bars use ars styled using these CSS class names:
+ * -------------------------------------------------------
+ * vpScroll - The scroll bar container.
+ * vpScrollUp - The UP arrow.
+ * vpScrollCursor - The cursor used to slide within the bounds.
+ * vpScrollDown - The DOWN arrow.
+ *
+ *
  * Requires prototypejs 1.6+, DimpSlider.js, scriptaculous 1.8+ (effects.js
  * only), and Horde's dragdrop2.js.
  *
@@ -120,21 +150,30 @@ var ViewPort = Class.create({
         this.opts = Object.extend({
             buffer_pages: 10,
             limit_factor: 35,
-            lookbehind: 40
+            lookbehind: 40,
+            split_bar_class: {}
         }, opts);
 
-        this.opts.content = $(opts.content);
-        this.opts.split_pane = $(opts.split_pane);
+        this.opts.container = $(opts.container);
+        this.opts.pane_data = $(opts.pane_data);
+
+        this.opts.content = new Element('DIV', { className: opts.list_class }).setStyle({ overflow: 'hidden' });
+        this.opts.container.insert(this.opts.content);
 
         this.scroller = new ViewPort_Scroller(this);
-        this.template = new Template(opts.template);
 
+        this.split_pane = {
+            curr: null,
+            horiz: {
+                loc: opts.page_size,
+            },
+            vert: {}
+        };
         this.views = {};
 
-        this.split_bar_loc = opts.page_size;
-        this.show_split_pane = opts.show_split_pane;
+        this.pane_mode = opts.pane_mode;
 
-        this.isbusy = this.line_height = this.page_size = this.split_bar = null;
+        this.isbusy = this.page_size = null;
         this.request_num = 1;
 
         // Init empty string now.
@@ -158,7 +197,7 @@ var ViewPort = Class.create({
         // Need a page size before we can continue - this is what determines
         // the slice size to request from the server.
         if (this.page_size === null) {
-            ps = this.getPageSize(this.show_split_pane ? 'default' : 'max');
+            ps = this.getPageSize(this.pane_mode ? 'default' : 'max');
             if (isNaN(ps)) {
                 return this.loadView.bind(this, view, search, background).defer();
             }
@@ -336,8 +375,9 @@ var ViewPort = Class.create({
         this.isbusy = false;
     },
 
-    // nowait = (boolean) TODO
-    onResize: function(nowait)
+    // nowait = (boolean) If true, don't delay before resizing.
+    // size = (integer) The page size to use instead of auto-determining.
+    onResize: function(nowait, size)
     {
         if (!this.opts.content.visible()) {
             return;
@@ -348,55 +388,82 @@ var ViewPort = Class.create({
         }
 
         if (nowait) {
-            this._onResize();
+            this._onResize(size);
         } else {
-            this.resizefunc = this._onResize.bind(this).delay(0.1);
+            this.resizefunc = this._onResize.bind(this, size).delay(0.1);
         }
     },
 
-    _onResize: function()
+    // size = (integer) The page size to use instead of auto-determining.
+    _onResize: function(size)
     {
         // This is needed for IE 6 - or else horizontal scrolling can occur.
         if (!this.opts.content.offsetHeight) {
-            return this._onResize.bind(this).defer();
+            return this._onResize.bind(this, size).defer();
         }
 
-        var h, setpane,
-            c = $(this.opts.content),
+        var h,
+            c = this.opts.content,
             de = document.documentElement,
             lh = this._getLineHeight();
 
+        if (size) {
+            this.page_size = size;
+        }
+
         // Get split pane dimensions
-        if (this.opts.split_pane) {
-            if (this.show_split_pane) {
-                if (!this.opts.split_pane.visible()) {
-                    this._initSplitBar();
-                    if (this.split_bar_loc &&
-                        this.split_bar_loc > 0) {
-                        this.split_bar_loc = this.page_size = Math.min(this.split_bar_loc, this.getPageSize('splitmax'));
-                    } else {
-                        this.page_size = this.getPageSize('default');
-                    }
+        switch (this.pane_mode) {
+        case 'horiz':
+            this._initSplitBar();
+
+            if (!size) {
+                this.page_size = (this.split_pane.horiz.loc && this.split_pane.horiz.loc > 0)
+                    ? Math.min(this.split_pane.horiz.loc, this.getPageSize('splitmax'))
+                    : this.getPageSize('default');
+            }
+            this.split_pane.horiz.loc = this.page_size;
+
+            h = lh * this.page_size;
+            c.setStyle({ float: 'none', height: h + 'px', width: '100%' });
+            this.split_pane.currbar.show();
+            this.opts.pane_data.setStyle({ height: (this._getMaxHeight() - h - lh) + 'px' }).show();
+            break;
+
+        case 'vert':
+            this._initSplitBar();
+
+            if (!size) {
+                this.page_size = this.getPageSize('max');
+            }
+
+            h = lh * this.page_size;
+            // TODO: Configurable default size? Currently it is 35% of
+            // container size.
+            c.setStyle({ float: 'left', height: h + 'px', width: parseInt(this.opts.container.getWidth() * 0.35, 10) + 'px' });
+            this.split_pane.currbar.setStyle({ height: h + 'px' }).show();
+            this.opts.pane_data.setStyle({ height: h + 'px' }).show();
+            break;
+
+        default:
+            if (this.split_pane.curr) {
+                if (this.pane_mode == 'horiz') {
+                    this.split_pane.horiz.loc = this.page_size;
                 }
-                setpane = true;
-            } else if (this.opts.split_pane.visible()) {
-                this.split_bar_loc = this.page_size;
-                [ this.opts.split_pane, this.split_bar ].invoke('hide');
+                [ this.opts.pane_data, this.split_pane.currbar ].invoke('hide');
+                this.split_pane.curr = this.split_pane.currbar = null;
+            }
+
+            if (!size) {
+                this.page_size = this.getPageSize('max');
             }
-        }
 
-        if (!setpane) {
-            this.page_size = this.getPageSize('max');
+            c.setStyle({ float: 'none', height: (lh * this.page_size) + 'px', width: '100%' });
+            break;
         }
 
         // Do some magic to ensure we never cause a horizontal scroll.
-        h = lh * this.page_size;
-        c.setStyle({ height: h + 'px' });
-        if (setpane) {
-            this.opts.split_pane.setStyle({ height: (this._getMaxHeight() - h - lh) + 'px' }).show();
-            this.split_bar.show();
-        } else if (de.scrollHeight - de.clientHeight) {
-            c.setStyle({ height: (lh * (this.page_size - 1)) + 'px' });
+        if (de.scrollHeight - de.clientHeight) {
+            c.setStyle({ height: (parseInt(c.getStyle('height'), 10) - lh) + 'px' });
         }
 
         this.scroller.onResize();
@@ -771,16 +838,7 @@ var ViewPort = Class.create({
             r.bg.push('vpRowSelected');
         }
 
-        r.bg.unshift('vpRow');
-
-        if (this.opts.onContent) {
-            this.opts.onContent(r);
-        }
-
-        // Mandatory DOM ID and class information.
-        r.vpData = 'id="' + r.domid + '" class="' + r.bg.join(' ') + '"';
-
-        return this.template.evaluate(r);
+        return this.opts.onContent(r, this.pane_mode);
     },
 
     updateRow: function(row)
@@ -855,19 +913,22 @@ var ViewPort = Class.create({
 
     _getLineHeight: function()
     {
-        if (!this.line_height) {
+        var mode = this.pane_mode || 'horiz';
+
+        if (!this.split_pane[mode].lh) {
             // To avoid hardcoding the line height, create a temporary row to
             // figure out what the CSS says.
-            var d = new Element('DIV', { className: this.opts.content_class }).insert(new Element('DIV', { className: 'vpRow' })).hide();
+            var d = new Element('DIV', { className: this.opts.list_class }).insert(this.prepareRow({ domid: null }, mode)).hide();
             $(document.body).insert(d);
-            this.line_height = d.getHeight();
+            this.split_pane[mode].lh = d.getHeight();
             d.remove();
         }
 
-        return this.line_height;
+        return this.split_pane[mode].lh;
     },
 
     // (type) = (string) [null (DEFAULT), 'current', 'default', 'max']
+    // return: (integer) Number of rows in current view.
     getPageSize: function(type)
     {
         switch (type) {
@@ -875,11 +936,13 @@ var ViewPort = Class.create({
             return Math.min(this.page_size, this.getMetaData('total_rows'));
 
         case 'default':
-            return Math.max(parseInt(this.getPageSize('max') * 0.45), 5);
+            return (this.pane_mode == 'vert')
+                ? this.getPageSize('max')
+                : Math.max(parseInt(this.getPageSize('max') * 0.45), 5);
 
         case 'max':
         case 'splitmax':
-            return parseInt((this._getMaxHeight() - (type == 'max' ? 0 : 100)) / this._getLineHeight());
+            return parseInt(this._getMaxHeight() / this._getLineHeight()) - (type == 'max' ? 0 : 1);
 
         default:
             return this.page_size;
@@ -902,68 +965,109 @@ var ViewPort = Class.create({
         return Math.round(this.bufferSize() * (this.opts.limit_factor / 100));
     },
 
-    showSplitPane: function(show)
+    // mode = (string) Either 'horiz', 'vert', or empty.
+    showSplitPane: function(mode)
     {
-        this.show_split_pane = show;
+        this.pane_mode = mode;
         this.onResize(true);
     },
 
     _initSplitBar: function()
     {
-        if (this.split_bar) {
+        if (this.split_pane.currbar) {
+            this.split_pane.currbar.hide();
+        }
+
+        this.split_pane.curr = this.pane_mode;
+
+        if (this.split_pane[this.pane_mode].bar) {
+            this.split_pane.currbar = this.split_pane[this.pane_mode].bar.show();
             return;
         }
 
-        this.split_bar = $(this.opts.split_bar);
-        new Drag(this.split_bar, {
-            constraint: 'vertical',
-            ghosting: true,
-            nodrop: true,
-            onStart: function() {
-                // Cache these values since we will be using them multiple
-                // times in snap().
-                this.sp = {
-                    lh: this._getLineHeight(),
-                    lines: this.page_size,
-                    max: this.getPageSize('splitmax'),
-                    orig: this.page_size,
-                    pos: $(this.opts.content).positionedOffset()[1]
-                };
-                if (this.opts.onSplitBarStart) {
-                    this.opts.onSplitBarStart();
-                }
-            }.bind(this),
-            snap: function(x, y, elt) {
-                var l = parseInt((y - this.sp.pos) / this.sp.lh);
-                if (l < 1) {
-                    l = 1;
-                } else if (l > this.sp.max) {
-                    l = this.sp.max;
-                }
-                this.sp.lines = l;
-                return [ x, this.sp.pos + (l * this.sp.lh) ];
-            }.bind(this),
-            onEnd: function() {
-                this.page_size = this.sp.lines;
-                this.onResize(true);
+        this.split_pane.currbar = this.split_pane[this.pane_mode].bar = new Element('DIV', { className: this.opts.split_bar_class[this.pane_mode] });
+
+        if (!this.opts.pane_data.descendantOf(this.opts.container)) {
+            this.opts.container.insert({ bottom: this.opts.pane_data.remove() });
+        }
+
+        this.opts.pane_data.insert({ before: this.split_pane.currbar });
+
+        switch (this.pane_mode) {
+        case 'horiz':
+            new Drag(this.split_pane.currbar, {
+                constraint: 'vertical',
+                ghosting: true,
+                nodrop: true,
+                onStart: function() {
+                    // Cache these values since we will be using them multiple
+                    // times in snap().
+                    this.sp = {
+                        lh: this._getLineHeight(),
+                        lines: this.page_size,
+                        max: this.getPageSize('splitmax'),
+                        orig: this.page_size,
+                        pos: this.opts.content.positionedOffset()[1]
+                    };
+                    if (this.opts.onSplitBarStart) {
+                        this.opts.onSplitBarStart('horiz');
+                    }
+                }.bind(this),
+                snap: function(x, y, elt) {
+                    var l = parseInt((y - this.sp.pos) / this.sp.lh);
+                    if (l < 1) {
+                        l = 1;
+                    } else if (l > this.sp.max) {
+                        l = this.sp.max;
+                    }
+                    this.sp.lines = l;
+                    return [ x, this.sp.pos + (l * this.sp.lh) ];
+                }.bind(this),
+                onEnd: function() {
+                    this.onResize(true, this.sp.lines);
+                    if (this.opts.onSplitBarChange &&
+                        this.sp.orig != this.sp.lines) {
+                        this.opts.onSplitBarChange('horiz');
+                    }
+                    if (this.opts.onSplitBarEnd) {
+                        this.opts.onSplitBarEnd('horiz');
+                    }
+                }.bind(this)
+            });
+
+            this.split_pane.currbar.observe('dblclick', function() {
+                var old_size = this.page_size;
+                this.onResize(true, this.getPageSize('default'));
                 if (this.opts.onSplitBarChange &&
-                    this.sp.orig != this.sp.lines) {
-                    this.opts.onSplitBarChange();
-                }
-                if (this.opts.onSplitBarEnd) {
-                    this.opts.onSplitBarEnd();
+                    old_size != this.page_size) {
+                    this.opts.onSplitBarChange('horiz');
                 }
-            }.bind(this)
-        });
-        this.split_bar.observe('dblclick', function() {
-            var old_size = this.page_size;
-            this.page_size = this.getPageSize('default');
-            this._onResize(true);
-            if (this.opts.onSplitBarChange &&
-                old_size != this.page_size) {
-                this.opts.onSplitBarChange();
-            }
-        }.bind(this));
+            }.bind(this));
+            break;
+
+        case 'vert':
+            new Drag(this.split_pane.currbar.setStyle({ float: 'left' }), {
+                constraint: 'horizontal',
+                ghosting: true,
+                nodrop: true,
+                snapToParent: true,
+                onStart: function(drag) {
+                    if (this.opts.onSplitBarStart) {
+                        this.opts.onSplitBarStart('vert');
+                    }
+                }.bind(this),
+                onEnd: function(drag) {
+                    this.opts.content.setStyle({ width: drag.lastCoord[0] + 'px' });
+                    if (this.opts.onSplitBarChange && drag.wasDragged) {
+                        this.opts.onSplitBarChange('vert');
+                    }
+                    if (this.opts.onSplitBarEnd) {
+                        this.opts.onSplitBarEnd('vert');
+                    }
+                }.bind(this)
+            });
+            break;
+        }
     },
 
     createSelection: function(format, data, view)
@@ -1055,7 +1159,7 @@ ViewPort_Scroller = Class.create({
         var c = this.vp.opts.content;
 
         // Create the outer div.
-        this.scrollDiv = new Element('DIV', { className: 'sbdiv' }).setStyle({ height: c.getHeight() + 'px' }).hide();
+        this.scrollDiv = new Element('DIV', { className: 'vpScroll' }).setStyle({ height: c.getHeight() + 'px', overflow: 'hidden', position: 'absolute', right: 0, top: 0 }).hide();
 
         // Add scrollbar to parent viewport and give our parent a right
         // margin just big enough to accomodate the scrollbar.
@@ -1063,8 +1167,8 @@ ViewPort_Scroller = Class.create({
 
         // Create scrollbar object.
         this.scrollbar = new DimpSlider(this.scrollDiv, {
-            buttonclass: { up: 'sbup', down: 'sbdown' },
-            cursorclass: 'sbcursor',
+            buttonclass: { up: 'vpScrollUp', down: 'vpScrollDown' },
+            cursorclass: 'vpScrollCursor',
             onChange: this._onScroll.bind(this),
             onSlide: this.vp.opts.onSlide ? this.vp.opts.onSlide : null,
             pagesize: this.vp.getPageSize(),
@@ -1216,10 +1320,10 @@ ViewPort_Buffer = Class.create({
                 this._rangeCheck($A($R(Math.max(offset + 1 - this.vp.limitTolerance(), 1), offset)))) {
                 return 'top';
             } else if (this._rangeCheck($A($R(offset + 1, Math.min(offset + this.vp.limitTolerance() + this.vp.getPageSize() - 1, this.getMetaData('total_rows')))).reverse())) {
-                // Search for missing messages in reverse order since in
-                // normal usage (sequential scrolling through the message
-                // list) messages are more likely to be missing at furthest
-                // from the current view.
+                // Search for missing rows in reverse order since in normal
+                // usage (sequential scrolling through the row list) rows are
+                // more likely to be missing at furthest from the current
+                // view.
                 return 'bottom';
             }
         }
index 4206c90..a50ebc0 100644 (file)
@@ -2,12 +2,7 @@
  * mailbox-dimp.js - Template used to format the rows in the message list
  * display.
  *
- * 'vpData' is a mandatory entry for ID/class information automatically
- * generated by ViewPort.js.
- * 'status', 'style', and 'subjectdata' are entries that are internally
- * created by DimpBase.js.
- *
- * See the documentation of prototypejs - Template for the template format:
+ * See the documentation of prototypejs::Template for the template format:
  *   http://www.prototypejs.org/api/template
  *
  * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
@@ -16,8 +11,8 @@
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
  */
 
-DimpBase.message_list_template =
-'<div #{vpData} style="#{style}">' +
+DimpBase.msglist_template_horiz =
+'<div class="#{className}" id="#{domid}" style="#{style}">' +
  '<div class="msgStatus sep">' +
   '<div class="msCheck"></div>' +
   '#{status}' +
@@ -27,3 +22,18 @@ DimpBase.message_list_template =
  '<div class="msgDate sep">#{date}</div>' +
  '<div class="msgSize">#{size}</div>' +
 '</div>';
+
+DimpBase.msglist_template_vert =
+'<div class="#{className}" id="#{domid}" style="#{style}">' +
+ '<div class="msgStatus">' +
+  '<div class="msCheck"></div>' +
+  '#{status}' +
+ '</div>' +
+ '<div>' +
+  '<div class="msgFrom">#{from}</div>' +
+  '<div class="msgDate">#{date}</div>' +
+ '</div>' +
+ '<div>' +
+  '<div class="msgSubject" title="#{subjecttitle}">#{subjectdata}#{subject}</div>' +
+ '</div>' +
+'</div>';
index a29c956..fb67f61 100644 (file)
@@ -191,122 +191,119 @@ function _simpleButton($id, $text, $image)
      </div>
     </div>
 
-    <div class="msgSplitPane">
-     <div id="msgList" class="msglist">
-      <span class="vpEmpty"><?php echo _("Loading...") ?></span>
-     </div>
-     <div id="splitBar" style="display:none"></div>
-     <div id="previewPane" style="display:none">
-      <span id="msgLoading" class="loadingImg" style="display:none"></span>
-      <div id="previewInfo" style="display:none">
-       <?php echo _("To preview a message, select it from the list above.") ?>
-       <br />
+    <div id="msgSplitPane"></div>
+
+    <div id="previewPane" style="display:none">
+     <span id="msgLoading" class="loadingImg" style="display:none"></span>
+     <div id="previewInfo" style="display:none">
+      <?php echo _("To preview a message, select it from the list above.") ?>
+      <br />
 <?php if ($browser->isBrowser('opera')): ?>
-       <?php echo _("A left click") ?> + <span class="kbd"><?php echo _("Shift") ?></span> + <span class="kbd"><?php echo _("Ctrl") ?></span> <?php echo _("will display available actions.") ?>
+      <?php echo _("A left click") ?> + <span class="kbd"><?php echo _("Shift") ?></span> + <span class="kbd"><?php echo _("Ctrl") ?></span> <?php echo _("will display available actions.") ?>
 <?php else: ?>
-       <?php echo _("A right-click on a message or a folder will display available actions.") ?>
-<?php endif; ?>
-       <br />
-       <?php printf(_("Click on a message while holding down the %s key to select multiple messages.  To select a range of messages, click the first message of the range, navigate to the last message of the range, and then click on the last message while holding down the %s key."), '<span class="kbd">' . _("Ctrl") . '</span>', '<span class="kbd">' . _("Shift") . '</span>') ?><br /><br />
-       <?php echo _("The following keyboard shortcuts are available:") ?><br />
-       <span class="iconImg keyupImg"></span> / <span class="iconImg keydownImg"></span> : <?php echo _("Move up/down through the message list.") ?><br />
-       <span class="kbd"><?php echo _("PgUp") ?></span> / <span class="kbd"><?php echo _("PgDown") ?></span> : <?php echo _("Move one page up/down through the message list.") ?><br />
-       <span class="kbd"><?php echo _("Alt") ?></span> + <span class="kbd"><?php echo _("PgUp") ?></span> / <span class="kbd"><?php echo _("PgDown") ?></span> : <?php echo _("Scroll up/down through the display of the previewed message.") ?><br />
-       <span class="kbd"><?php echo _("Home") ?></span> / <span class="kbd"><?php echo _("End") ?></span> : <?php echo  _("Move to the beginning/end of the message list.") ?><br />
-       <span class="kbd"><?php echo _("Del") ?></span> : <?php echo _("Delete the currently selected message(s).") ?> <?php printf(_("%s will delete the current message and move to the next message if a single message is selected."), '<span class="kbd">' . _("Shift") . '</span> + <span class="kbd">' . _("Del") . '</span>') ?><br />
-       <span class="kbd"><?php echo _("Enter") ?></span> : <?php echo _("Open message in a popup window.") ?><br />
-       <span class="kbd"><?php echo _("Ctrl") ?></span> + <span class="kbd"><?php echo 'A' ?></span> : <?php echo _("Select all messages in the current mailbox.") ?><br />
-      </div>
-      <div id="previewMsg" style="display:none">
-       <div class="msgHeaders">
-        <div id="toggleHeaders">
-         <a id="th_expand"><span class="iconImg" title="<?php echo htmlspecialchars(_("Expand Headers")) ?>"></span></a>
-         <a id="th_collapse" style="display:none"><span class="iconImg" title="<?php echo htmlspecialchars(_("Collapse Headers")) ?>"></span></a>
-        </div>
-        <div id="msgHeadersColl">
-         <a id="msg_newwin"><span class="iconImg" title="<?php echo htmlspecialchars(_("Open in new window")) ?>"></span></a>
-         <span class="date"></span>
-         <span class="subject"></span>
-         <span class="fromcontainer"><?php echo _("from") ?> <span class="from"></span></span>
-        </div>
-        <div id="msgHeaders" style="display:none">
-         <div class="dimpOptions">
-          <div>
-           <span id="msg_newwin_options">
-            <span class="iconImg"></span>
-            <a><?php echo _("Open in new window") ?></a>
-           </span>
-          </div>
-          <div>
-           <span id="msg_print">
-            <span class="iconImg"></span>
-            <a><?php echo _("Print") ?></a>
-           </span>
-          </div>
+      <?php echo _("A right-click on a message or a folder will display available actions.") ?>
+<?php endif; ?>
+      <br />
+      <?php printf(_("Click on a message while holding down the %s key to select multiple messages.  To select a range of messages, click the first message of the range, navigate to the last message of the range, and then click on the last message while holding down the %s key."), '<span class="kbd">' . _("Ctrl") . '</span>', '<span class="kbd">' . _("Shift") . '</span>') ?><br /><br />
+      <?php echo _("The following keyboard shortcuts are available:") ?><br />
+      <span class="iconImg keyupImg"></span> / <span class="iconImg keydownImg"></span> : <?php echo _("Move up/down through the message list.") ?><br />
+      <span class="kbd"><?php echo _("PgUp") ?></span> / <span class="kbd"><?php echo _("PgDown") ?></span> : <?php echo _("Move one page up/down through the message list.") ?><br />
+      <span class="kbd"><?php echo _("Alt") ?></span> + <span class="kbd"><?php echo _("PgUp") ?></span> / <span class="kbd"><?php echo _("PgDown") ?></span> : <?php echo _("Scroll up/down through the display of the previewed message.") ?><br />
+      <span class="kbd"><?php echo _("Home") ?></span> / <span class="kbd"><?php echo _("End") ?></span> : <?php echo  _("Move to the beginning/end of the message list.") ?><br />
+      <span class="kbd"><?php echo _("Del") ?></span> : <?php echo _("Delete the currently selected message(s).") ?> <?php printf(_("%s will delete the current message and move to the next message if a single message is selected."), '<span class="kbd">' . _("Shift") . '</span> + <span class="kbd">' . _("Del") . '</span>') ?><br />
+      <span class="kbd"><?php echo _("Enter") ?></span> : <?php echo _("Open message in a popup window.") ?><br />
+      <span class="kbd"><?php echo _("Ctrl") ?></span> + <span class="kbd"><?php echo 'A' ?></span> : <?php echo _("Select all messages in the current mailbox.") ?><br />
+     </div>
+
+     <div id="previewMsg" style="display:none">
+      <div class="msgHeaders">
+       <div id="toggleHeaders">
+        <a id="th_expand"><span class="iconImg" title="<?php echo htmlspecialchars(_("Expand Headers")) ?>"></span></a>
+        <a id="th_collapse" style="display:none"><span class="iconImg" title="<?php echo htmlspecialchars(_("Collapse Headers")) ?>"></span></a>
+       </div>
+       <div id="msgHeadersColl">
+        <a id="msg_newwin"><span class="iconImg" title="<?php echo htmlspecialchars(_("Open in new window")) ?>"></span></a>
+        <span class="date"></span>
+        <span class="subject"></span>
+        <span class="fromcontainer"><?php echo _("from") ?> <span class="from"></span></span>
+       </div>
+       <div id="msgHeaders" style="display:none">
+        <div class="dimpOptions">
+         <div>
+          <span id="msg_newwin_options">
+           <span class="iconImg"></span>
+           <a><?php echo _("Open in new window") ?></a>
+          </span>
+         </div>
+         <div>
+          <span id="msg_print">
+           <span class="iconImg"></span>
+           <a><?php echo _("Print") ?></a>
+          </span>
+         </div>
 <?php if (!empty($conf['user']['allow_view_source'])): ?>
-          <div>
-           <span id="msg_view_source">
-            <span class="iconImg"></span>
-            <a><?php echo _("View Source") ?></a>
-           </span>
-          </div>
-<?php endif; ?>
+         <div>
+          <span id="msg_view_source">
+           <span class="iconImg"></span>
+           <a><?php echo _("View Source") ?></a>
+          </span>
          </div>
-         <div id="msgHeadersContent">
-          <table>
-           <thead>
-            <tr>
-             <td class="label"><?php echo _("Subject") ?>:</td>
-             <td class="subject"></td>
-            </tr>
-            <tr id="msgHeaderFrom">
-             <td class="label"><?php echo _("From") ?>:</td>
-             <td class="from"></td>
-            </tr>
-            <tr id="msgHeaderDate">
-             <td class="label"><?php echo _("Date") ?>:</td>
-             <td class="date"></td>
-            </tr>
-            <tr id="msgHeaderTo">
-             <td class="label"><?php echo _("To") ?>:</td>
-             <td class="to"></td>
-            </tr>
-            <tr id="msgHeaderCc">
-             <td class="label"><?php echo _("Cc") ?>:</td>
-             <td class="cc"></td>
-            </tr>
-            <tr id="msgAtc" style="display:none">
-             <td class="label" id="partlist_toggle">
-              <span class="iconImg attachmentImg attachmentImage"></span>
-              <span class="iconImg" id="partlist_col"></span>
-              <span class="iconImg" id="partlist_exp" style="display:none"></span>
-              </td>
-             <td>
-              <div></div>
-              <div id="partlist" style="display:none">
-               <table></table>
-              </div>
-             </td>
-            </tr>
-            <tr id="msgLogInfo" style="display:none">
-             <td class="label" id="msgloglist_toggle">
-              <span class="iconImg" id="msgloglist_col"></span>
-              <span class="iconImg" id="msgloglist_exp" style="display:none"></span>
-             </td>
-             <td>
-              <div><span class="msgLogLabel"><?php echo _("Message Log") ?></span></div>
-              <div id="msgloglist" style="display:none">
-               <ul></ul>
-              </div>
+<?php endif; ?>
+        </div>
+        <div id="msgHeadersContent">
+         <table>
+          <thead>
+           <tr>
+            <td class="label"><?php echo _("Subject") ?>:</td>
+            <td class="subject"></td>
+           </tr>
+           <tr id="msgHeaderFrom">
+            <td class="label"><?php echo _("From") ?>:</td>
+            <td class="from"></td>
+           </tr>
+           <tr id="msgHeaderDate">
+            <td class="label"><?php echo _("Date") ?>:</td>
+            <td class="date"></td>
+           </tr>
+           <tr id="msgHeaderTo">
+            <td class="label"><?php echo _("To") ?>:</td>
+            <td class="to"></td>
+           </tr>
+           <tr id="msgHeaderCc">
+            <td class="label"><?php echo _("Cc") ?>:</td>
+            <td class="cc"></td>
+           </tr>
+           <tr id="msgAtc" style="display:none">
+            <td class="label" id="partlist_toggle">
+             <span class="iconImg attachmentImg attachmentImage"></span>
+             <span class="iconImg" id="partlist_col"></span>
+             <span class="iconImg" id="partlist_exp" style="display:none"></span>
              </td>
-            </tr>
-           </thead>
-          </table>
-         </div>
+            <td>
+             <div></div>
+             <div id="partlist" style="display:none">
+              <table></table>
+             </div>
+            </td>
+           </tr>
+           <tr id="msgLogInfo" style="display:none">
+            <td class="label" id="msgloglist_toggle">
+             <span class="iconImg" id="msgloglist_col"></span>
+             <span class="iconImg" id="msgloglist_exp" style="display:none"></span>
+            </td>
+            <td>
+             <div><span class="msgLogLabel"><?php echo _("Message Log") ?></span></div>
+             <div id="msgloglist" style="display:none">
+              <ul></ul>
+             </div>
+            </td>
+           </tr>
+          </thead>
+         </table>
         </div>
        </div>
-       <div id="messageBody" class="messageBody"></div>
       </div>
+      <div id="messageBody" class="messageBody"></div>
      </div>
     </div>
    </div>
@@ -417,6 +414,8 @@ function _simpleButton($id, $text, $image)
 <div class="context" id="ctx_otheractions" style="display:none">
  <a id="oa_preview_hide"><span class="contextImg"></span><?php echo _("Hide Preview") ?></a>
  <a id="oa_preview_show"><span class="contextImg"></span><?php echo _("Show Preview") ?></a>
+ <a id="oa_layout_horiz"><span class="contextImg"></span><?php echo _("Horizontal Layout") ?></a>
+ <a id="oa_layout_vert"><span class="contextImg"></span><?php echo _("Vertical Layout") ?></a>
 <?php if (!empty($flag_list)): ?>
  <div>
   <div class="sep"></div>
index 15f6bab..46a6811 100644 (file)
@@ -70,7 +70,7 @@ $code['conf'] = array_filter(array(
     'name' => $GLOBALS['registry']->get('name', 'imp'),
     'popup_height' => 610,
     'popup_width' => 820,
-    'preview_pref' => intval($GLOBALS['prefs']->getValue('dimp_show_preview')),
+    'preview_pref' => $GLOBALS['prefs']->getValue('dimp_show_preview'),
     'qsearchid' => IMP_Search::MBOX_PREFIX . IMP_Search::DIMP_QUICKSEARCH,
     'qsearchfield' => $GLOBALS['prefs']->getValue('dimp_qsearch_field'),
     'refresh_time' => intval($GLOBALS['prefs']->getValue('refresh_time')),
diff --git a/imp/themes/graphics/dragHandleVert.png b/imp/themes/graphics/dragHandleVert.png
new file mode 100644 (file)
index 0000000..b8493ac
Binary files /dev/null and b/imp/themes/graphics/dragHandleVert.png differ
index 9a5506e..e04fe01 100644 (file)
@@ -6,7 +6,7 @@
     height: auto;
 }
 
-#sidebarPanel .sepfull, #splitBar, .context div.sep {
+#sidebarPanel .sepfull, .splitBar, .context div.sep {
     overflow: hidden;
 }
 
index b4c8c46..96a736e 100644 (file)
@@ -9,7 +9,7 @@
     overflow-y: auto;
 }
 
-.msgSplitPane {
+#msgSplitPane {
     width: 99.7%;
 }
 
index c450e1f..0c2f7a2 100644 (file)
@@ -86,19 +86,32 @@ input {
 }
 
 /* SplitPane styles. */
-.msgSplitPane {
+#msgSplitPane {
     border-left: 1px silver solid;
     border-right: 1px silver solid;
     border-bottom: 1px silver solid;
     position: relative;
 }
-#splitBar {
-    background: #e9e9e9 url("graphics/dragHandle.png") no-repeat scroll center top !important;
+.splitBarHoriz, .splitBarVert {
+    background: #e9e9e9 no-repeat scroll;
     border: 1px solid silver;
-    cursor: n-resize;
-    height: 5px;
     z-index: 10;
 }
+.splitBarHoriz {
+    background-image: url("graphics/dragHandle.png");
+    background-position: center top;
+    cursor: ns-resize;
+    height: 5px;
+}
+.splitBarVert {
+    background-image: url("graphics/dragHandleVert.png");
+    background-position: center;
+    cursor: ew-resize;
+    height: 300px;
+    margin-bottom: -1px;
+    margin-top: -1px;
+    width: 5px;
+}
 
 /* Message List */
 .mboxheader {
@@ -108,10 +121,6 @@ input {
     position: absolute;
     margin: 10px 0 0 10px;
 }
-#msgLoading {
-    /* Positioned relative to .splitBar, which is 7px high by default. */
-    margin-top: 17px;
-}
 
 /* Columns */
 div.msgStatus {
@@ -147,6 +156,7 @@ div.msgSize {
     font-weight: bold;
     overflow: hidden;
     border: 1px solid silver;
+    border-top: 0;
     background: transparent url("graphics/backhead_orderby.png") repeat-x;
 }
 #msglistHeader a {
@@ -174,10 +184,6 @@ div.msgSize {
 }
 
 /* Message ViewPort */
-.msglist {
-    overflow: hidden;
-    width: 100%;
-}
 .msglist span.vpEmpty, .msglist span.vpError {
     font-weight: bold;
 }
@@ -192,23 +198,25 @@ div.msgSize {
     -o-text-overflow: ellipsis;
     height: 16px;
     border-bottom: 1px;
-    text-indent: 2px;
 }
 .msglist div.vpRowSelected {
     background: #ffa !important;
 }
-.msglist div.vpRow div.sep {
+.msglist div.vpRowHoriz div.sep {
     border-right: 1px solid #ddd;
 }
+.msglist div.vpRowHoriz, .msglist div.vpRowHoriz div {
+    text-indent: 2px;
+}
 
 /* Rows: flags. */
-div.vpRow.flagLowpriority {
+div.flagLowpriority {
     font-weight: normal !important;
 }
-div.vpRow.flagUnseen {
+div.flagUnseen {
     font-weight: bold;
 }
-div.vpRow.flagDeleted {
+div.flagDeleted {
     text-decoration: line-through;
 }
 
@@ -223,29 +231,49 @@ div.vpRow.flagDeleted {
     background-image: url("graphics/checkbox_on.png");
 }
 
-/* Scroller */
-.sbdiv {
+/* Rows (vertical mode) */
+.msglist div.vpRowVert {
+    height: auto;
+}
+.msglist div.vpRowVert div.msgStatus {
+    height: 24px;
+    padding-right: 4px;
+    padding-top: 8px;
+    width: 20%;
+}
+.msglist div.vpRowVert div.msgFrom {
+    font-weight: bold;
+    width: auto;
+}
+.msglist div.vpRowVert div.msgDate {
+    float: right;
+    text-indent: 2px;
+    width: auto;
+}
+.msglist div.vpRowVert div.msgSubject {
+    float: none;
+    font-style: italic;
+    width: auto;
+}
+
+/* ViewPort - scroller */
+.vpScroll {
     background: url("graphics/scroller_back.png") repeat-y;
-    overflow: hidden;
-    position: absolute;
-    right: 0;
-    top: 0;
-    width: 14px;
 }
-.sbcursor {
+.vpScrollCursor {
     background: url("graphics/scroller.png") repeat-y;
     border-left: 1px solid silver;
     width: 13px;
 }
-.sbup, .sbdown {
+.vpScrollDown, .vpScrollUp {
     border-left: 1px solid silver;
     height: 16px;
     width: 13px;
 }
-.sbup {
+.vpScrollUp {
     background-image: url("graphics/sbcursor_top.png");
 }
-.sbdown {
+.vpScrollDown {
     background-image: url("graphics/sbcursor_bottom.png");
 }
 
@@ -362,7 +390,6 @@ div.vpRow.flagDeleted {
     background: #efefef;
     padding: 4px 2px;
     border: 1px silver solid;
-    border-bottom: 0;
     background: transparent url("graphics/backhead_s2.png") repeat-x;
     height: 16px;
 }
@@ -408,6 +435,7 @@ div.vpRow.flagDeleted {
     cursor: default;
     margin: 0;
 }
+
 #button_compose, #button_checkmail {
     display: none;
 }
@@ -1021,7 +1049,7 @@ span.readonlyImg {
         overflow: visible !important;
     }
 
-    .msgSplitPane {
+    #msgSplitPane {
         border: 0;
     }
 
@@ -1029,7 +1057,7 @@ span.readonlyImg {
         display: block !important;
     }
 
-    #sidebarPanel, #dimpmain_folder_top, #msgList, div.sbdiv, #splitBar, #toggleHeaders, #Growler, #GrowlerLog, #writemsg, .dimpActions, .dimpOptions {
+    #sidebarPanel, #dimpmain_folder_top, #msgSplitPane .msglist, div.sbdiv, .splitBar, #toggleHeaders, #Growler, #GrowlerLog, #writemsg, .dimpActions, .dimpOptions {
         display: none !important;
     }