wip: UI refactoring

* ckeditor support re-introduced into the webmail
* smarter way to retrieve capabilities

see #204
This commit is contained in:
Antoine Nguyen
2012-04-20 17:23:54 +02:00
parent e9a8842a5d
commit fc8c36fb05
3 changed files with 72 additions and 34 deletions
+46 -33
View File
@@ -31,9 +31,9 @@ class capability(object):
def __call__(self, method):
@wraps(method)
def wrapped_func(cls, *args, **kwargs):
if self.name in cls.m.capabilities:
if self.name in cls.capabilities:
return method(cls, *args, **kwargs)
return getattr(cls, self.fallback_method)(*args, **kwargs)
return getattr(cls, self.fallback_method)(cls, **kwargs)
return wrapped_func
@@ -131,9 +131,7 @@ class IMAPconnector(object):
self.criterions = []
self.address = parameters.get_admin("IMAP_SERVER")
self.port = int(parameters.get_admin("IMAP_PORT"))
status, msg = self.login(user, password)
if not status:
raise WebmailError(msg)
self.login(user, password)
def _cmd(self, name, *args, **kwargs):
"""IMAP command wrapper
@@ -216,14 +214,20 @@ class IMAPconnector(object):
if hasattr(self, "current_mailbox"):
del self.current_mailbox
else:
return
status, msg = self.login(user, password)
if not status:
raise ImapError(msg)
return
self.login(user, password)
def login(self, user, passwd):
import socket
"""Custom login method
We connect to the server, issue a LOGIN command. If
successfull, we try to record a eventuel CAPABILITY untagged
response. Otherwise, we issue the command.
:param user: username
:param passwd: password
"""
import socket
try:
secured = parameters.get_admin("IMAP_SECURED")
if secured == "yes":
@@ -231,19 +235,23 @@ class IMAPconnector(object):
else:
self.m = imaplib.IMAP4(self.address, self.port)
except (socket.error, imaplib.IMAP4.error, ssl.SSLError), error:
return False, _("Connection to IMAP server failed, check your configuration")
try:
self.m.login(user, passwd)
except (imaplib.IMAP4.error, ssl.SSLError), error:
return False, _("Authentication failed, check your configuration")
return True, None
raise ImapError(_("Connection to IMAP server failed: %s" % error))
data = self._cmd("LOGIN", user, passwd)
self.m.state = "AUTH"
if self.m.untagged_responses.has_key("CAPABILITY"):
self.capabilities = \
self.m.untagged_responses.pop('CAPABILITY')[0].split()
else:
data = self._cmd("CAPABILITY")
self.capabilities = data[0].split()
def logout(self):
try:
self.m.select()
except imaplib.IMAP4.error:
self._cmd("CHECK")
except ImapError, e:
pass
self.m.logout()
self._cmd("LOGOUT")
del self.m
self.m = None
@@ -303,7 +311,7 @@ class IMAPconnector(object):
:return: an integer
"""
data = self._cmd("STATUS", mailbox.encode("imap4-utf-7"), "(UNSEEN)")
m = self.unseen_pattern.match(data[0])
m = self.unseen_pattern.match(data[-1])
if m is None:
return 0
return int(m.group(1))
@@ -329,12 +337,24 @@ class IMAPconnector(object):
sdescr["class"] = "subfolders"
return True
def _listmboxes_simple(self, topmailbox='INBOX', md_mailboxes=[]):
def _listmboxes_simple(self, topmailbox='INBOX', mailboxes=[], **kwargs):
#data = self._cmd("LIST", "", "*")
(status, data) = self.m.list()
result = []
newmboxes = []
for mb in data:
flags, delimiter, name = self.list_response_pattern.match(mb).groups()
name = name.strip('"').decode("imap4-utf-7")
pos = -1
for idx, mdm in enumerate(mailboxes):
if mdm["name"] == name:
pos = idx
break
if pos == -1:
descr = dict(name=name)
newmboxes += [descr]
else:
descr = mailboxes[idx]
if re.search("\%s" % delimiter, name):
parts = name.split(".")
if not descr.has_key("path"):
@@ -344,18 +364,11 @@ class IMAPconnector(object):
parts[1:]):
descr["class"] = "subfolders"
continue
present = False
descr = {"name" : name}
for mdf in md_mailboxes:
if mdf["name"] == name:
present = True
break
if not present:
result += [descr]
from operator import itemgetter
return sorted(result, key=itemgetter("name"))
@capability('LIST-EXTENDED', '_listfolders_simple')
from operator import itemgetter
mailboxes += sorted(newmboxes, key=itemgetter("name"))
@capability('LIST-EXTENDED', '_listmboxes_simple')
def _listmboxes(self, topmailbox='', mailboxes=[], until_mailbox=None):
pattern = ("%s.%%" % topmailbox.encode("imap4-utf-7")) if len(topmailbox) else "%"
resp = self._cmd("LIST", "", pattern, "RETURN", "(CHILDREN)")
@@ -513,7 +526,7 @@ class IMAPconnector(object):
return True
def getquota(self, mailbox):
if not "QUOTA" in self.m.capabilities:
if not "QUOTA" in self.capabilities:
self.quota_limit = self.quota_actual = None
return
+25 -1
View File
@@ -160,6 +160,7 @@ Webmail.prototype = {
/*if (this.gspinner) {
this.gspinner.hide();
}*/
$(window).unbind("resize");
if (response.menu != undefined) {
$("#menubar").html(response.menu);
$("#searchfield").searchbar({navobj: this.navobject});
@@ -679,6 +680,9 @@ Webmail.prototype = {
e.preventDefault();
$link.attr("disabled", "disabled");
if (this.editormode == "html") {
CKEDITOR.instances[this.editorid].updateElement();
}
$.ajax({
url: $form.attr("action"),
data: args,
@@ -696,7 +700,7 @@ Webmail.prototype = {
e.preventDefault();
if ($tr.hasClass("unseen")) {
var mb = this.navobject.params["name"];
var mb = this.get_current_mailbox();
this.change_unseen_messages(mb, -1);
}
this.navobject.reset().setparams({
@@ -737,8 +741,28 @@ Webmail.prototype = {
*
* It is also shared with other similar actions : reply, forward.
*/
resize_editor: function() {
CKEDITOR.instances[this.editorid].resize("100%",
$("#body_container").outerHeight(true));
},
compose_callback: function(resp) {
this.page_update(resp);
this.editormode = resp.editor;
if (resp.editor == "html") {
var instance = CKEDITOR.instances[this.editorid];
$(window).resize($.proxy(this.resize_editor, this));
if (instance) {
CKEDITOR.remove(instance);
}
CKEDITOR.replace(this.editorid, {
customConfig: static_url("js/editor_config.js")
});
CKEDITOR.on("instanceReady", $.proxy(function(evt) {
this.resize_editor();
}, this));
}
if (resp.id != undefined) {
this.navobject.setparam("id", resp.id).update(false, true);
}
@@ -3,6 +3,7 @@
{% block html_head %}
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}webmail/css/webmail.css" />
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery-ui.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.htmltable.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/searchbar.js"></script>