diff --git a/extensions/webmail/static/css/webmail.css b/extensions/webmail/static/css/webmail.css index 7c9a7c60c..1e988e462 100644 --- a/extensions/webmail/static/css/webmail.css +++ b/extensions/webmail/static/css/webmail.css @@ -1,114 +1,128 @@ -#listing { - position: absolute; - left: 160px; - right: 0px; - top: 130px; - height: expression(document.body.clientHeight - 35 + "px"); +body, html { + overflow: hidden; + height: 100%; +} + +#leftcol { + /*position: fixed; + top: 60px; + left: 0; + width: 200px; + padding-left: 15px; + overflow: hidden;*/ +} + +#folders { + position: fixed; + top: 60px; + left: 15px; + width: 200px; + overflow-y: auto; + margin-bottom: 5px; +} + +#mboxes_container { overflow: auto; } -html > body #listing { +#menubar { position: fixed; - bottom: 35px; + left: 215px; + padding-left: 15px; } -body.loading { - display: block; - filter: alpha(opacity=50); - opacity: 0.5; - z-index: 3; - background: #FFF url("../../css/spinner.gif") center center no-repeat; +#listing { + position: fixed; + left: 215px; + right: 0; + padding-left: 15px; } -.clearfix:after { - content: "."; - display: block; - clear: both; - visibility: hidden; - overflow: hidden; - line-height: 0; - height: 0; -} - -.clearfix { - display: inline-block; -} - -html[xmlns] .clearfix { - display: block; -} - -* html .clearfix { - height: 1%; - overflow: visible; -} - -/*thead tr { - position: relative; - top: expression(offsetParent.scrollTop); - z-index: 1; - padding: 0; -}*/ - -/*table#emails > tbody { - position: fixed; - bottom: 35px; - top: 155px; - left: 155px; - right: 0px; - overflow-x: hidden; - overflow-y: auto; -}*/ - -#emails th { - /*position: relative;*/ -} - -#emails th input { - margin: 0; -} - -#emails tr { - width: 100%; - border-bottom: 1px solid #C8D6E8; - user-select: none; /* CSS3 */ - -moz-user-select: none; /* Gecko (Firefox) */ - -khtml-user-select: none; /* Webkit (Safari, Chrome) */ -} - -.draggable { - cursor: move; - /*position: relative;*/ +#mailcontent { border: 0; + margin: 0; + padding: 0; + width: 100%; + height: 100%; } -.draggable img { - position: static; +.unseen { + font-weight: bold; } -ul.hidden { - display: none; +td[name="date"] { + text-align: right; } -ul.visible { - display: block; - padding-bottom: 0; +#quotabar { + margin: 12px 0 0 15px; + width: 200px; } -/* Compose mail page */ -#compose-container { +#quotaraw { + margin-left: 10px; +} + +/* + * Mailboxes list + */ +#mboxactions { + position: fixed; + padding-left: 14px; +} + +#mboxactions .btn-toolbar { + margin-bottom: 0px; +} + +#folders li { + position: relative; +} + +div.clickbox { position: absolute; left: 0px; - right: 10px; - top: 0; - bottom: 0; + top: 2px; + width: 14px; + height: 14px; +} + +div.collapsed { + background-image: url("/static/pics/collapsed.png"); + background-repeat: no-repeat; +} + +div.expanded { + background-image: url("/static/pics/expanded.png"); + background-repeat: no-repeat; +} + +/* + * Compose form + */ +#mailheader { + position: relative; + padding-bottom: 5px; +} + +#mailheader input { + width: 99%; + padding: 2px 0; +} + +#mailheader textarea { + width: 99%; + height: 40px; + padding: 2px 0; +} + +#mailheader label { + text-align: left; } #attachments { position: relative; - border: 1px solid #cccccc; - background-color: #eee; - margin: 10px 0 5px 0; + margin: 1px 0 5px 0; padding: 5px 0; cursor: pointer; width: 100%; @@ -121,133 +135,65 @@ ul.visible { #list { position: absolute; top: 5px; - left: 130px; + left: 160px; font-weight: bold; } +#body_container { + position: absolute; + left: 15px; + right: 0px; + bottom: 15px; +} + +#id_body { + width: 99%; + height: 100%; +} + +/* + * Attachments form + */ +#submit { + margin: 0 auto; +} + +#attachment_list { + margin-top: 20px; + height: 150px; + overflow-x: hidden; + overflow-y: auto; + padding: 2px; +} + +#attachment_list i, +#attachment_list label { + float: left; +} + .shortlist { font-weight: normal !important; font-style: italic; } -div.row { - width: 100%; - margin: 5px 0; -} - -div.row label { - width: 120px; - font-size: small; - padding: 3px 0; -} - -div.input_container { - position: static; - margin-left: 130px; -} - -textarea { - border: 1px solid #cccccc; - background-color: #eee; - width: 100%; - height: 40px; - word-wrap: break-word; - resize: none; - padding: 2px 0; -} - -textarea:hover { - background-color: #ffffcc; -} - -#body_container { - position: absolute; - top: 205px; - left: 0; - right: 0px; - bottom: 15px; -} - -#id_body { - background: white; - width: 100%; - height: 100%; -} - -#mailheader input { - width: 100%; - padding: 2px 0; -} - -#mailheader { - position: relative; - padding-bottom: 5px; -} - -/* Progress bar */ -#quotalabel { - float: left; - padding: 7px 2px 0 5px; - display: none; -} - -#quotabox { - display: none; - float: left; - margin: 5px; - width: 300px; - padding: 0; -} - -#box { - /*border: 1px solid #ccc; */ - width: 200px; - background: url(../../pics/progressbar_bg.gif) right center no-repeat; - height: 19px; - float: left; -} - -#perc { - background: url(../../pics/progressbar.gif) right center no-repeat; - height: 19px; -} - -#quotatext { - padding: 2px 0 0 2px; - float: left; -} - -#fdmenu { border:1px solid #999; padding:0; background:#eee; width:150px; display:none; } -#fdmenu .separator { border-top:1px solid #999; } -#fdmenu ul { list-style-type:none; margin:0; padding:0; } -#fdmenu li { margin:0; padding:0; } -#fdmenu li a { display:block; padding:5px 10px 5px 5px; font-size:12px; text-decoration:none; font-family:tahoma,arial,sans-serif; color:#000; } -#fdmenu li a:hover { background-color:#ddd; } -#fdmenu img { float:left; margin: 0 5px 0 0; } - -.folder_menu { - float: right; - opacity: 0.8; -} - -.folder_btn { - float: right; - margin: 3px; -} - -.folder_menubar { - clear: both; -} - +/* + * Drap & Drop + */ .dragbox { - position : absolute; - opacity : 0.8; - width : 200px; padding : 5px; text-align : center; - height : 25px; - border : 1px solid #333; background : white; - display: none; z-index : 3; +} + +/* + * Folder form + */ +.modal-body { + max-height: 300px; + overflow-y: auto; +} + +#folders2 li { + position: relative; } \ No newline at end of file diff --git a/extensions/webmail/static/js/fdmenu.js b/extensions/webmail/static/js/fdmenu.js deleted file mode 100644 index 570d6e80d..000000000 --- a/extensions/webmail/static/js/fdmenu.js +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Simple dropdown menu plugin used for folders manipulation. - * - */ -var FdMenu = new Class({ - Implements: [Options], - - options: { - modify_url: "", - delete_url: "" - }, - - add_entry: function(name, label, pic, url, onclick) { - var item = new Element("li"); - var picpath = static_url("pics/" + pic); - - this[name] = new Element("a") - .set("html", " " + label) - .addEvent("click", onclick.bind(this)) - .inject(item); - item.inject(this.list); - }, - - initialize: function(options) { - this.setOptions(options); - - this.container = new Element("div", {"id" : "fdmenu"}) - .addClass("fdmenu"); - this.list = new Element("ul"); - - this.add_entry("modbutton", gettext("Edit folder"), - "edit.png", this.options.modify_url, function(evt) { - evt.stop(); - SqueezeBox.open(evt.target.get("href"), { - handler: "iframe", - size: {x: 350, y: 400}, - closeBtn: true - }); - $(document.body).fireEvent("click"); - }); - - this.add_entry("delbutton", gettext("Delete folder"), "remove.png", - this.options.delete_url, function(evt) { - evt.stop(); - $(document.body).fireEvent("click"); - if (!confirm(gettext("Delete folder?"))) { - return; - } - new Request.JSON.mdb({ - url: evt.target.get("href"), - method: "GET", - onSuccess: function(resp) { - if (resp.status == "ok") { - var dfolder = this.current_folder + "/"; - - if (dfolder == current_anchor.base) { - var pfolder = ((this.current_folder.split(".")).slice(0, -1)).join("."); - if (pfolder == "") { - pfolder = "INBOX"; - } - current_anchor.baseurl(pfolder, 1); - } - current_anchor.loading_message = gettext("Folder deleted"); - current_anchor.loading_color = "green"; - current_anchor.update(1); - } else { - infobox.error(resp.error); - infobox.hide(2); - } - }.bind(this) - }).send(); - } - ); - this.list.inject(this.container); - this.shown = false; - - $(document.body).addEvent("click", function() { - if (this.shown) { - this.hide(); - } - }.bind(this)); - }, - - show: function(origin, folder) { - var position = origin.getPosition(); - - this.container.setStyles({ - position: "absolute", - top: position.y + 5, - left: position.x + 5, - display: "block" - }); - this.container.inject(document.body); - this.shown = true; - this.current_folder = folder; - this.modbutton.set("href", this.options.modify_url + "?name=" + folder); - this.delbutton.set("href", this.options.delete_url + "?name=" + folder); - }, - - hide: function() { - this.container.setStyles({ - display: "none" - }); - this.container = this.container.dispose(); - this.shown = false; - }, - - toggle: function(origin, folder) { - return (!this.shown) ? this.show(origin, folder) : this.hide(); - } -}); \ No newline at end of file diff --git a/extensions/webmail/static/js/webmail.js b/extensions/webmail/static/js/webmail.js index 6ec536852..622cf2b98 100644 --- a/extensions/webmail/static/js/webmail.js +++ b/extensions/webmail/static/js/webmail.js @@ -1,533 +1,589 @@ -var Webmail = new Class({ - Implements: [Options], +/* + * The javascript code that brings the webmail to life! + */ +var Webmail = function(options) { + this.initialize(options); +}; + +Webmail.prototype = { + constructor: Webmail, - /* - * Default values for options - */ defaults: { - refreshRate: 0, - modify_url: "", - delete_url: "", + poller_interval: 300, /* in seconds */ + poller_url: "", move_url: "", - submboxes_url: "" + submboxes_url: "", + delattachment_url: "", + deflocation: "", + defcallback: "", + ro_mboxes: ["INBOX"] }, - /* - * Constructor - */ initialize: function(options) { - this.setOptions(options); - + this.options = $.extend({}, this.defaults, options); this.rtimer = null; this.editorid = "id_body"; - this.init_folders_buttons(); - this.init_folders_browsing(); - this.init_quota_bar(); - - /* FIXME: à faire uniquement pour le mode pushState */ - /*this.init_emails_table();*/ - - current_anchor.disable_spinner(); - current_anchor.register_callback("listmailbox", - this.listmailbox_callback.bind(this)); - current_anchor.register_callback("viewmail", this.viewmail_callback.bind(this)); - current_anchor.register_callback("compose", this.compose_callback.bind(this)); - current_anchor.register_callback("reply", this.compose_callback.bind(this)); - current_anchor.register_callback("replyall", this.compose_callback.bind(this)); - current_anchor.register_callback("forward", this.compose_callback.bind(this)); - current_anchor.register_callback("delete", this.delete_callback); - - this.gspinner = new Spinner("document.body", { - message: gettext("Loading, please wait..."), - 'class': "spinner-noop" + this.navobject = new History({ + deflocation: this.options.deflocation, + defcallback: this.options.defcallback }); - this.gspinner.addEvent("hide", function(target) { - this.gspinner.destroy(); - delete(this.gspinner); - current_anchor.enable_spinner(); - }.bind(this)); - this.gspinner.show(); + this.poller = new Poller(this.options.poller_url, { + interval: this.options.poller_interval * 1000, + success_cb: $.proxy(this.poller_cb, this), + args: this.get_visible_mailboxes + }); + this.record_unseen_messages(); + + $("#folders").css({ + bottom: $("#bottom-bar").outerHeight(true) + }); + $("#mboxactions").css({ + bottom: $("#bottom-bar").outerHeight(true) + 10 + }); + this.resize(); + + this.init_droppables(); + this.register_navcallbacks(); + this.listen(); }, - send_mark_request: function(evt) { - evt.stop(); - if (!this.emails_table._selectedRows.length) { - return; - } - var ids = new Array(); + register_navcallbacks: function() { + this.navobject.register_callback("listmailbox", + $.proxy(this.listmailbox_callback, this)); + this.navobject.register_callback("compose", + $.proxy(this.compose_callback, this)); + this.navobject.register_callback("viewmail", + $.proxy(this.viewmail_callback, this)); - this.emails_table._selectedRows.each(function(item, index) { - ids.include(item.get("id")); - }); - this.simple_request(evt.target.get("href"), { - ids : ids.join() - }, function(response) { - if (response.action == "read") { - this.emails_table._selectedRows.removeClass("unseen"); - } else { - this.emails_table._selectedRows.addClass("unseen"); - } - /* - * MAJ de l'affichage du nombre de messages non lus - * (faire fonction à part) - */ - }.bind(this)); + this.navobject.register_callback("reply", + $.proxy(this.compose_callback, this)); + this.navobject.register_callback("replyall", + $.proxy(this.compose_callback, this)); + this.navobject.register_callback("forward", + $.proxy(this.compose_callback, this)); + this.navobject.register_callback("delete", + $.proxy(this.delete_callback, this)); + }, + + listen: function() { + $(window).resize(this.resize); + + $(document).on("click", "a[name=compose]", + $.proxy(this.compose_loader, this)); + $(document).on("click", "a[name*=mark-]", + $.proxy(this.send_mark_request, this)); + $(document).on("click", "a[name=empty]", + $.proxy(this.empty, this)); + $(document).on("click", "#bottom-bar a", + $.proxy(this.getpage_loader, this)); + + $(document).on("click", "a[name=loadfolder]", + $.proxy(this.listmailbox_loader, this)); + $(document).on("click", "a[name=selectfolder]", + this.select_parent_mailbox), + $(document).on("click", "div[class*=clickbox]", + $.proxy(this.mbox_state_callback, this)); + $(document).on("click", "a[name=editmbox]", + $.proxy(this.edit_mbox, this)); + $(document).on("click", "a[name=removembox]", + $.proxy(this.remove_mbox, this)); + + $(document).on("dblclick", "tbody>tr", + $.proxy(this.viewmail_loader, this)); + + $(document).on("click", "a[name=reply]", + $.proxy(this.reply_loader, this)); + $(document).on("click", "a[name=replyall]", + $.proxy(this.reply_loader, this)); + $(document).on("click", "a[name=forward]", + $.proxy(this.reply_loader, this)); + $(document).on("click", "a[name=delete]", + $.proxy(this.delete_message, this)); + $(document).on("click", "a[name=activate_links]", + $.proxy(function(e) { this.display_mode(e, "1"); }, this)); + $(document).on("click", "a[name=disable_links]", + $.proxy(function(e) { this.disable_mode(e, "0"); }, this)); + + $(document).on("click", "a[name=sendmail]", + $.proxy(this.sendmail, this)); + + $(document).on("click", "#attachments", $.proxy(function(e) { + var $div = $(e.target).parent(); + modalbox(e, undefined, $div.attr("name"), + $.proxy(this.attachments_init, this)); + }, this)); + }, + + record_unseen_messages: function() { + var unseen_counters = {}; + + $("#folders").find("a.unseen").each(function() { + var $this = $(this); + unseen_counters[$this.attr("href")] = parseInt($this.attr("data-toggle")); + }); + this.unseen_counters = unseen_counters; + }, + + resize: function() { + $("#mboxes_container").height($("#folders").height() - $("#mboxactions").height()); }, /* - * Open/Close the menu containing folder buttons + * Simple helper to retrieve the currently selected mailbox. */ - toggle_folder_buttons: function(evt) { - var parent = evt.target.getParent(); - var fdname = parent.getFirst("a[name=loadfolder]").get("href"); - - this.fdmenu.toggle(evt.target, fdname); - evt.stop(); + get_current_mailbox: function() { + if (this.navobject.params.action != "listmailbox") { + return null; + } + return (this.navobject.params.name) + ? this.navobject.params.name : "INBOX"; }, /* - * Initializes the misc. buttons available to manipulate folders. + * Enable or disable edit and remove actions for the currently + * selected mailbox. */ - init_folders_buttons: function() { - $$("li[class*=clickable]").removeEvents(); - - $$("a[name=loadfolder]").addEvent("click", this.listmailbox_loader.bind(this)); - - SqueezeBox.assign($("folders").getElements('a[class=boxed]'), { - parse: 'rel' - }); - - this.fdmenu = new FdMenu({ - modify_url: this.options.modify_url, - delete_url: this.options.delete_url - }); - - $$("img[class*=footer]") - .addEvent("click", this.toggle_folder_buttons.bind(this)); - }, - - /* - * Open/Close a mailbox with children - */ - toggle_mbox_state: function(div, ul) { - if (ul.hasClass("hidden")) { - div.removeClass("collapsed").addClass("expanded"); - ul.removeClass("hidden").addClass("visible"); + enable_mb_actions: function(state) { + if (state === undefined) { + state = true; + } + if (state) { + $("a[name=editmbox], a[name=removembox]").removeClass("disabled"); } else { - div.removeClass("expanded").addClass("collapsed"); - ul.removeClass("visible").addClass("hidden"); + $("a[name=editmbox], a[name=removembox]").addClass("disabled"); + } + }, + + page_update: function(response) { + /*if (this.gspinner) { + this.gspinner.hide(); + }*/ + if (response.menu != undefined) { + $("#menubar").html(response.menu); + $("#searchfield").searchbar({navobj: this.navobject}); + } + if (response.navbar) { + $("#bottom-bar-right").html(response.navbar); + } + $("#listing").html(response.listing); + $("#listing").css({ + top: $("#menubar").outerHeight(true) + 60 + "px", + bottom: $("#bottom-bar").outerHeight(true) + "px", + overflow: "auto" + }); + }, + + /* + * Set the *unseen messages* counter for a particular mailbox in + * the list. If the mailbox is currently selected, we update the + * listing. + */ + set_unseen_messages: function(mailbox, value) { + if (this.poller.running_request) { + return; + } + if (this.unseen_counters[mailbox] != undefined + && value == this.unseen_counters[mailbox]) { + return; + } + + if (this.navobject.params.action == "listmailbox") { + var curmb = this.get_current_mailbox(); + if (curmb == mailbox) { + this.navobject.update(true); + } + } + + var $link = $('a[href="' + mailbox + '"]'); + var parts = mailbox.split('.'); + var dname = " " + parts[parts.length - 1]; + var $i = $link.children("i"); + + this.unseen_counters[mailbox] = value; + if (value) { + $link.html(dname + " (" + value + ")"); + $link.addClass("unseen"); + } else { + $link.html(dname); + $link.removeClass("unseen"); + } + $link.prepend($i); + }, + + /* + * Increment or decrement the *unseen messages* counter of the + * given mailbox. + */ + change_unseen_messages: function(mailbox, offset) { + if (this.unseen_counters[mailbox] === undefined) { + this.unseen_counters[mailbox] = 0; + } + this.set_unseen_messages(mailbox, this.unseen_counters[mailbox] + offset); + }, + + /* + * Returns a list containing the currently visible mailboxes (in + * the left tree). + */ + get_visible_mailboxes: function() { + var res = new Array(); + + $("#folders").find("ul:visible").children("li.droppable").each(function() { + res.push($(this).attr("name")); + }); + return "mboxes=" + res.join(","); + }, + + /* + * Sends a refresh request to the server. This method is called + * periodically to check for new messages. (not really optimized) + */ + update_unseen_messages: function(mailbox) { + $.ajax({ + url: this.options.poller_url + "?selection=" + mailbox, + dataType: 'json', + success: $.proxy(this.poller_cb, this) + }); + }, + + /* + * Poller callback. + */ + poller_cb: function(data) { + for (var mb in data.counters) { + this.set_unseen_messages(mb, parseInt(data.counters[mb])); } }, /* * Inject new mailboxes under a given parent in the tree. */ - inject_mailboxes: function(parent, mboxes) { - var ul = new Element("ul", { - name: parent.get("name"), - 'class': "hidden" - }).inject(parent); + inject_mailboxes: function($parent, mboxes) { + var $ul = $("