Thanks for throwing this up here Ryan. Here's an updated patch (for svn 410) that also works in IE and Opera in addition to Firefox. (Can someone test Safari?) This one also resizes the splitter bar when the window is resized. The setting still isn't saved in user_prefs but I'm sure Ryan will have that working soon... peace, David Glick
I really am batting 1000 today. Here's the diff. Going to bed.
--- program/include/main.inc (revision 410) +++ program/include/main.inc (working copy) @@ -1277,6 +1277,7 @@ // GENERAL 'loginform' => 'rcmail_login_form', 'username' => 'rcmail_current_username',
'splitter' => 'rcube_splitter',
// MAIL
'mailboxlist' => 'rcmail_mailbox_list',
@@ -1912,7 +1913,19 @@ return $select->show($set); }
+function rcube_splitter($attrib)
{
global $OUTPUT, $JS_OBJECT_NAME;
// register splitter in the system
$OUTPUT->add_script(sprintf("%s.register_splitter('%s', '%s', '%s');",
$JS_OBJECT_NAME,
$attrib['first'],
$attrib['second'],
$attrib['orientation']));
}
/****** debugging functions ********/
--- program/js/common.js (revision 410) +++ program/js/common.js (working copy) @@ -380,6 +380,187 @@ }
+/**
+function rcube_splitter(attrib)
this.layer = new rcube_layer(this.id, {x: this.p1pos.x, y: top,
height: height, zindex: 1, vis: 1});
this.layer = new rcube_layer(this.id, {x: left, y:
this.p1pos.y, width: width, zindex: 1, vis: 1});
this.elm.style.paddingTop = Math.floor(height / 2) + 'px';
this.elm.style.paddingLeft = Math.floor(width / 2) + 'px';
{
this.line.style.borderTopWidth = '1px';
this.line.style.width = '100%';
this.line.style.height = '1px';
}
{
this.line.style.borderLeftWidth = '1px';
this.line.style.width = '1px';
this.line.style.height = '100%';
}
object:this, method:'onMouseOver'});
object:this, method:'onMouseOut'});
object:this, method:'onDrag'});
object:this, method:'onDragStop'});
splitter stops moving when we move over an iframe
{
var iframedoc = null;
if (iframes[n].contentDocument)
iframedoc = iframes[n].contentDocument;
else if (iframes[n].contentWindow)
iframedoc = iframes[n].contentWindow.document;
else if (iframes[n].document)
iframedoc = iframes[n].document;
if (iframedoc)
{
// I don't use the add_listener function for this one because
I need to create closures to fetch
// the position of each iframe when the event is received
var s = this;
var id = iframes[n].id;
this.iframe_events[n] = function(e){ e._rc_pos_offset =
rcube_get_object_pos(document.getElementById(id)); return s.onDrag(e); }
if (iframedoc.addEventListener)
iframedoc.addEventListener('mousemove',
this.iframe_events[n], false);
else if (iframes[n].attachEvent)
iframedoc.attachEvent('onmousemove', this.iframe_events[n]);
else
iframedoc['onmousemove'] = this.iframe_events[n];
rcube_event.add_listener({element:iframedoc, event:'mouseup',
object:this, method:'onDragStop'});
}
}
{
pos.x += e._rc_pos_offset.x;
pos.y += e._rc_pos_offset.y;
}
{
if (((pos.y - this.layer.height * 1.5) > this.p1pos.y) &&
((pos.y + this.layer.height * 1.5) < (this.p2pos.y + this.p2.offsetHeight)))
{
// resize the panels
this.p2.style.top = Math.round(pos.y + this.layer.height / 2
this.p1.style.height = Math.round(pos.y - this.p1pos.y -
this.layer.height / 2 - 1) + 'px';
// move the splitter handle
this.layer.move(this.layer.x, Math.round(pos.y -
this.layer.height / 2 + 1));
}
}
{
if (((pos.x - this.layer.width * 1.5) > this.p1pos.x) &&
((pos.x + this.layer.width * 1.5) < (this.p2pos.x + this.p2.offsetWidth)))
{
this.p1.style.width = Math.round(pos.x - this.p1pos.x -
this.layer.width / 2 - 1) + 'px';
this.p2.style.left = Math.round(pos.x + this.layer.width / 2
this.layer.move(Math.round(pos.x - this.layer.width / 2 + 1),
this.layer.y);
}
}
object:this, method:'onDrag'});
object:this, method:'onDragStop'});
{
var iframedoc;
if (iframes[n].contentDocument)
iframedoc = iframes[n].contentDocument;
else if (iframes[n].contentWindow)
iframedoc = iframes[n].contentWindow.document;
else if (iframes[n].document)
iframedoc = iframes[n].document;
if (iframedoc)
{
if (this.iframe_events[n]) {
if (iframedoc.removeEventListener)
iframedoc.removeEventListener('mousemove',
this.iframe_events[n], false);
else if (iframedoc.detachEvent)
iframedoc.detachEvent('onmousemove', this.iframe_events[n]);
else
iframedoc['onmousemove'] = null;
}
rcube_event.remove_listener({element:iframedoc,
event:'mouseup', object:this, method:'onDragStop'});
}
}
// check if input is a valid email address // By Cal Henderson cal@iamcal.com // http://code.iamcal.com/php/rfc822/ Index: program/js/app.js =================================================================== --- program/js/app.js (revision 410) +++ program/js/app.js (working copy) @@ -24,6 +24,7 @@ this.env = new Object(); this.labels = new Object(); this.buttons = new Object();
@@ -78,6 +79,13 @@ };
p2, orientation: orientation});
@@ -108,6 +116,10 @@
// enable general commands
this.enable_command('logout', 'mail', 'addressbook', 'settings', true);
// initialize splitters
for (var n in this.splitters)
this.splitters[n].init();
switch (this.task) {
--- skins/default/common.css (revision 410) +++ skins/default/common.css (working copy) @@ -213,7 +213,21 @@ border: 1px solid #CCCCCC; }
+.splitter +{
+}
+.splitterLine +{
+}
/***** common table settings ******/
table.records-table thead tr td Index: skins/default/templates/mail.html =================================================================== --- skins/default/templates/mail.html (revision 410) +++ skins/default/templates/mail.html (working copy) @@ -55,6 +55,7 @@
</div>
<roundcube:if condition="config:preview_pane == true" /> +<roundcube:object name="splitter" first="mailcontframe" second="mailpreviewframe" orientation="horizontal" />
<div id="mailpreviewframe"> <roundcube:object name="messagecontentframe" id="messagecontframe" width="100%" height="100%" frameborder="0" src="/watermark.html" /> </div> Index: skins/default/templates/addressbook.html =================================================================== --- skins/default/templates/addressbook.html (revision 410) +++ skins/default/templates/addressbook.html (working copy) @@ -31,6 +31,8 @@ <roundcube:object name="addresslist" id="contacts-table" class="records-table" cellspacing="0" summary="Contacts list" /> </div>
+<roundcube:object name="splitter" first="addresslist" second="contacts-box" orientation="vertical" />
<div id="contacts-box"> <roundcube:object name="addressframe" id="contact-frame" width="100%" height="100%" frameborder="0" src="/watermark.html" /> </div> Index: skins/default/addresses.css =================================================================== --- skins/default/addresses.css (revision 410) +++ skins/default/addresses.css (working copy) @@ -70,10 +70,19 @@ border: 1px solid #999999; overflow: hidden; /* css hack for IE */ - width: expression((parseInt(document.documentElement.clientWidth)-530)+'px'); + width: expression((parseInt(document.documentElement.clientWidth)-80-document.getElementById('addresslist').offsetWidth)+'px'); height: expression((parseInt(document.documentElement.clientHeight)-135)+'px'); }
+#addresslist_contacts-box_splitter +{
+}
body.iframe, #contact-frame { Index: skins/default/mail.css =================================================================== --- skins/default/mail.css (revision 410) +++ skins/default/mail.css (working copy) @@ -131,9 +131,16 @@ background-color: #F9F9F9; /* css hack for IE */ width: expression((parseInt(document.documentElement.clientWidth)-240)+'px');
}
+#mailcontframe_mailpreviewframe_splitter +{
+}
#messagecontframe { width: 100%;
Thanks a lot Ryan and David for contributing the splitter code. It is available in SVN trunk now.
I've changed it a bit and took it away from the core functions and added it to the skins folder. It now reads and writes cookies in order to save the state. There are some little visual differences between Firefox, IE and Safari which are caused by different interpretations of DomObj.offsetTop and DomObj.offsetHeight. I hope I can get rid of them one day...
Saving the state to a cookie and applying it on load is not the best choice because you can see the objects moving from their initial size to the saved size. To omit this effect, RoundCube will have to learn how to save GUI objects properties and read them right when the page HTML is created...
Regards, Thomas
David Glick wrote:
Thanks for throwing this up here Ryan. Here's an updated patch (for svn 410) that also works in IE and Opera in addition to Firefox. (Can someone test Safari?) This one also resizes the splitter bar when the window is resized. The setting still isn't saved in user_prefs but I'm sure Ryan will have that working soon... peace, David Glick
On Dec 17, 2006, at 4:34 PM, Thomas Bruederli wrote:
Thanks a lot Ryan and David for contributing the splitter code. It is available in SVN trunk now.
I've installed trunk (412) on my OpenBSD server and am testing it
with Safari. I like where it's going (running 385 in production),
but I'm seeing some odd bugs. These seem to only happen the first
time I open a folder (including after login to INBOX). I haven't
figured out exactly which actions trigger each event, but they are
reproducible.
(replacing the pane, message list and folder list)
2) Select a message, it opens the message in the right-half of the
window (replacing the pane and message list)
3) Select a message, it starts to load the message in the pane, but
then goes back to the default (empty) pane image
4) With a message selected, I press the down arrow on my keyboard,
and the 2nd email further down the message list is selected. If I
press up, the 2nd email up the list is selected. Conversely, the
same action in Firefox simply scrolls the mail within the pane.
After any of the first three types of events, it seems to operate
normally. Select any message and it loads properly in the preview
pane. However, as soon as I select a new folder, event #1 happens
every time. If I can be of any further assistance with testing,
please let me know.
P.S. Firefox on the Mac seems to work fine. A friend also tested
Firefox and IE on Windows and has not encountered any problems.
Thanks,
-- Jason Dixon DixonGroup Consulting http://www.dixongroup.net