diff --git a/modoboa/extensions/sievefilters/templates/sievefilters/filter.html b/modoboa/extensions/sievefilters/templates/sievefilters/filter.html index bd51ecdbb..e0476c0b4 100644 --- a/modoboa/extensions/sievefilters/templates/sievefilters/filter.html +++ b/modoboa/extensions/sievefilters/templates/sievefilters/filter.html @@ -1,5 +1,8 @@ {% extends "common/generic_modal_form.html" %} {% load i18n form_tags sfilters_tags %} + +{% block modal_css_classes %}modal-lg{% endblock %} + {% block formbody %} {% if oldname %}{% endif %} {% render_field form.name %} diff --git a/modoboa/extensions/webmail/lib/__init__.py b/modoboa/extensions/webmail/lib/__init__.py index bf1f4b89f..0f0b166b3 100644 --- a/modoboa/extensions/webmail/lib/__init__.py +++ b/modoboa/extensions/webmail/lib/__init__.py @@ -6,7 +6,6 @@ from .imapemail import ImapEmail, ReplyModifier, ForwardModifier from .imaputils import ( BodyStructure, IMAPconnector, get_imapconnector, separate_mailbox ) -from .listing import ImapListing from .signature import EmailSignature from .utils import decode_payload, WebmailNavigationParameters from .sendmail import send_mail @@ -20,7 +19,6 @@ __all__ = [ 'ForwardModifier', 'IMAPconnector', 'ImapEmail', - 'ImapListing', 'ReplyModifier', 'WebmailNavigationParameters', 'clean_attachments', diff --git a/modoboa/extensions/webmail/lib/imaputils.py b/modoboa/extensions/webmail/lib/imaputils.py index 5b4447f8c..d087306f4 100644 --- a/modoboa/extensions/webmail/lib/imaputils.py +++ b/modoboa/extensions/webmail/lib/imaputils.py @@ -141,6 +141,9 @@ class BodyStructure(object): class IMAPconnector(object): + + """The IMAPv4 connector.""" + __metaclass__ = ConnectionsManager list_base_pattern = r'\((?P.*?)\) "(?P.*)" "?(?P[^"]*)"?' @@ -300,6 +303,32 @@ class IMAPconnector(object): del self.m self.m = None + def parse_search_parameters(self, criterion, pattern): + """Parse search information and apply them.""" + + def or_criterion(old, c): + if old == "": + return c + return "OR (%s) (%s)" % (old, c) + + if criterion == u"both": + criterion = u"from_addr, subject" + criterions = "" + if type(pattern) is unicode: + pattern = pattern.encode("utf-8") + if type(criterion) is unicode: + criterion = criterion.encode("utf-8") + for c in criterion.split(','): + if c == "from_addr": + key = "FROM" + elif c == "subject": + key = "SUBJECT" + else: + continue + criterions = \ + or_criterion(criterions, '(%s "%s")' % (key, pattern)) + self.criterions = [criterions] + def messages_count(self, **kwargs): """An enhanced version of messages_count @@ -456,7 +485,9 @@ class IMAPconnector(object): from operator import itemgetter mailboxes += sorted(newmboxes, key=itemgetter("name")) - def getmboxes(self, user, topmailbox='', until_mailbox=None, unseen_messages=True): + def getmboxes( + self, user, topmailbox='', until_mailbox=None, + unseen_messages=True): """Returns a list of mailboxes for a particular user By default, only the first level of mailboxes under @@ -588,23 +619,33 @@ class IMAPconnector(object): return True def getquota(self, mailbox): + """Retrieve quota information from the server. + + We also compute the current usage. + """ if not "QUOTA" in self.capabilities: - self.quota_limit = self.quota_actual = None + self.quota_limit = self.quota_current = None return data = self._cmd("GETQUOTAROOT", self._encode_mbox_name(mailbox), responses=["QUOTAROOT", "QUOTA"]) if data is None: - self.quota_limit = self.quota_actual = None + self.quota_limit = self.quota_current = None return quotadef = data[1][0] - m = re.search("\(STORAGE (\d+) (\d+)\)", quotadef) + m = re.search(r"\(STORAGE (\d+) (\d+)\)", quotadef) if not m: print "Problem while parsing quota def" return self.quota_limit = int(m.group(2)) - self.quota_actual = int(m.group(1)) + self.quota_current = int(m.group(1)) + try: + self.quota_usage = ( + int(float(self.quota_current) / float(self.quota_limit) * 100) + ) + except TypeError: + self.quota_usage = -1 def fetchpart(self, uid, mbox, partnum): """Retrieve a specific message part diff --git a/modoboa/extensions/webmail/lib/listing.py b/modoboa/extensions/webmail/lib/listing.py deleted file mode 100644 index 80d0927d4..000000000 --- a/modoboa/extensions/webmail/lib/listing.py +++ /dev/null @@ -1,107 +0,0 @@ -from django.conf import settings -from django.utils.translation import ugettext_lazy - -from modoboa.lib import parameters, tables -from modoboa.lib.email_listing import EmailListing -from . import IMAPconnector, imapheader - - -class WMtable(tables.Table): - - """Webmail listing table.""" - - tableid = "emails" - styles = "table-hover" - idkey = "imapid" - drag = tables.ImgColumn( - "drag", cssclass="draggable left", - defvalue="%spics/grippy.png" % settings.STATIC_URL, - header="" - ) - selection = tables.SelectionColumn( - "selection", safe=True, header=None, sortable=False - ) - flags = tables.ImgColumn("flags") - withatts = tables.ImgColumn("withatts") - subject = tables.Column( - "subject", label=ugettext_lazy("Subject"), limit=60, - cssclass="openable" - ) - from_ = tables.Column( - "from", label=ugettext_lazy("From"), limit=30, - cssclass="openable" - ) - date = tables.Column( - "date", label=ugettext_lazy("Date"), cssclass="openable" - ) - - cols_order = [ - "drag", "selection", "flags", "from_", "subject", "withatts", "date" - ] - - def parse(self, header, value): - if value is None: - return "" - try: - value = getattr(imapheader, "parse_%s" % header)(value) - except AttributeError: - pass - return value - - -class ImapListing(EmailListing): - tpl = "webmail/index.html" - tbltype = WMtable - deflocation = "INBOX/" - defcallback = "wm_updatelisting" - reset_wm_url = False - - def __init__(self, user, password, **kwargs): - self.user = user - self.mbc = IMAPconnector(user=user.username, password=password) - if "pattern" in kwargs and kwargs["pattern"]: - self.parse_search_parameters( - kwargs["criteria"], kwargs["pattern"] - ) - else: - self.mbc.criterions = [] - - super(ImapListing, self).__init__(**kwargs) - self.extravars["refreshrate"] = \ - int(parameters.get_user(user, "REFRESH_INTERVAL")) * 1000 - - def parse_search_parameters(self, criterion, pattern): - - def or_criterion(old, c): - if old == "": - return c - return "OR (%s) (%s)" % (old, c) - - if criterion == u"both": - criterion = u"from_addr, subject" - criterions = "" - if type(pattern) is unicode: - pattern = pattern.encode("utf-8") - if type(criterion) is unicode: - criterion = criterion.encode("utf-8") - for c in criterion.split(','): - if c == "from_addr": - key = "FROM" - elif c == "subject": - key = "SUBJECT" - else: - continue - criterions = \ - or_criterion(criterions, '(%s "%s")' % (key, pattern)) - self.mbc.criterions = [criterions] - - @staticmethod - def computequota(mbc): - try: - return int(float(mbc.quota_actual) \ - / float(mbc.quota_limit) * 100) - except (AttributeError, TypeError): - return -1 - - def getquota(self): - return ImapListing.computequota(self.mbc) diff --git a/modoboa/extensions/webmail/static/webmail/css/webmail.css b/modoboa/extensions/webmail/static/webmail/css/webmail.css index dd85f5f6b..6add291a7 100644 --- a/modoboa/extensions/webmail/static/webmail/css/webmail.css +++ b/modoboa/extensions/webmail/static/webmail/css/webmail.css @@ -46,9 +46,6 @@ } /* GENERAL */ -body, html { - /*overflow: hidden;*/ -} #rightcol { position: fixed; @@ -90,10 +87,6 @@ body, html { width: 8px; } -#mboxes_container { - /*overflow: auto;*/ -} - .nav-sidebar li > a { padding-top: 7px; padding-bottom: 7px; @@ -273,8 +266,9 @@ list { } /* - * Folder form + * Folders form */ + .modal-body { max-height: 300px; overflow-y: auto; @@ -284,6 +278,22 @@ list { position: relative; } +#folders2 div.clickbox { + left: 0; + top: 0px; +} + +#folders2 li li { + margin-left: 10px; +} + +#folders2 .active > a, +#folders2 .active > a:hover, +#folders2 .active > a:focus { + color: #fff; + background-color: #428bca; +} + /* * Table */ diff --git a/modoboa/extensions/webmail/static/webmail/js/webmail.js b/modoboa/extensions/webmail/static/webmail/js/webmail.js index d49de0ba8..6a356f39f 100644 --- a/modoboa/extensions/webmail/static/webmail/js/webmail.js +++ b/modoboa/extensions/webmail/static/webmail/js/webmail.js @@ -186,7 +186,7 @@ Webmail.prototype = { return $("#emails").height() - $element.height(); }, get_args: function() { - var args = that.navparams; + var args = $.extend({}, that.navparams); args.scroll = true; return args; }, @@ -281,6 +281,8 @@ Webmail.prototype = { /** * Simple helper to retrieve the currently selected mailbox. + * + * @this Webmail */ get_current_mailbox: function() { return this.navobject.getparam("mbox", "INBOX"); @@ -289,9 +291,11 @@ Webmail.prototype = { /** * Keep track of interesting navigation parameters in order to * restore them later. + * + * @this Webmail */ store_nav_params: function() { - var params = new Array("page", "order", "pattern", "criteria"); + var params = new Array("order", "pattern", "criteria"); this.navparams = {}; for (var idx in params) { @@ -299,9 +303,11 @@ Webmail.prototype = { } }, - /* + /** * Restore navigation parameters previously stored via * store_nav_params. + * + * @this Webmail */ restore_nav_params: function() { if (this.navparams === undefined) { @@ -360,12 +366,13 @@ Webmail.prototype = { } if (response.menu !== undefined) { $("#menubar").html(response.menu); - $("#searchfield").searchbar({navobj: this.navobject}); + $("#searchfield").searchbar({ + navobj: this.navobject, + pattern_changed: function(navobj) { + navobj.setparam("reset_page", "true"); + } + }); } - /*if (response.navbar) { - $("#pagination").html(response.navbar); - $("#pagination-responsive").html(response.navbar); - }*/ $("#listing").html(response.listing); @@ -525,7 +532,12 @@ Webmail.prototype = { * @param {Object} parent - parent node where mailboxes will be appended * @param {boolean} async - if true, the ajax call will be asynchronous */ - get_mailboxes: function(parent, async) { + get_mailboxes: function(parent, async, with_unseen) { + var args = "topmailbox=" + parent.attr("name"); + + if (with_unseen) { + args += "&unseen=true"; + } if (async === undefined) { async = true; } @@ -533,7 +545,7 @@ Webmail.prototype = { url: this.options.submboxes_url, dataType: 'json', async: async, - data: "topmailbox=" + parent.attr("name") + data: args }).done($.proxy(function(data) { this.inject_mailboxes(parent, data); }, this)); @@ -575,7 +587,9 @@ Webmail.prototype = { var $ul = $parent.find('ul[name="' + $parent.attr("name") + '"]'); if (!$ul.length) { - this.get_mailboxes($parent); + var $link = $div.next(); + var with_unseen = ($link.attr("name") == "loadfolder") ? true : false; + this.get_mailboxes($parent, true, with_unseen); return; } this.toggle_mbox_state($div, $ul); @@ -642,6 +656,12 @@ Webmail.prototype = { $('li[name="' + mailbox + '"]').addClass("active"); }, + /** + * Click handler : select the parent mailbox of the mailbox being + * created/modified. + * + * @param {Object} e - event object + */ select_parent_mailbox: function(e) { e.preventDefault(); var $this = $(this); @@ -808,6 +828,12 @@ Webmail.prototype = { }, this)); }, + /** + * Click event: empty Trash folder. + * + * @this Webmail + * @param {Object} e - event object + */ empty: function(e) { e.preventDefault(); var $link = $(e.target); @@ -894,7 +920,7 @@ Webmail.prototype = { } this.navobject.reset().setparams({ action: "listmailbox", - mbox: obj.attr("href"), + mbox: obj.attr("href") }); if (reset_page) { this.navobject.setparam("reset_page", reset_page); @@ -1061,16 +1087,19 @@ Webmail.prototype = { this.resize_compose_body(); }, - /* + /** * Callback of the 'viewmail' action + * + * @this Webmail + * @param {Object} resp - AJAX call response (JSON) */ viewmail_callback: function(resp) { this.page_update(resp); $("#listing").css("overflow", "hidden"); - // $("a[name=back]").click($.proxy(function(e) { - // e.preventDefault(); - // this.go_back_to_listing(); - // }, this)); + $("a[name=back]").click($.proxy(function(e) { + e.preventDefault(); + this.go_back_to_listing(); + }, this)); }, mark_callback: function(data) { diff --git a/modoboa/extensions/webmail/views.py b/modoboa/extensions/webmail/views.py index 1de405f76..c99d84334 100644 --- a/modoboa/extensions/webmail/views.py +++ b/modoboa/extensions/webmail/views.py @@ -19,6 +19,7 @@ from django.views.decorators.gzip import gzip_page from modoboa.lib import parameters from modoboa.lib.exceptions import ModoboaException, BadRequest +from modoboa.lib.paginator import Paginator from modoboa.lib.webutils import ( _render_to_string, ajax_response, render_to_json_response ) @@ -29,7 +30,7 @@ from .forms import ( ) from .lib import ( decode_payload, AttachmentUploadHandler, - save_attachment, ImapListing, EmailSignature, + save_attachment, EmailSignature, clean_attachments, set_compose_session, send_mail, ImapEmail, WebmailNavigationParameters, ReplyModifier, ForwardModifier, get_imapconnector, IMAPconnector, separate_mailbox @@ -337,7 +338,8 @@ def listmailbox(request, defmailbox="INBOX", update_session=True): parameter. (user preferences) :param request: a ``Request`` object - :param defmailbox: the default mailbox (when not present inside request arguments) + :param defmailbox: the default mailbox (when not present inside + request arguments) :return: a dictionnary """ navparams = WebmailNavigationParameters(request, defmailbox) @@ -345,30 +347,34 @@ def listmailbox(request, defmailbox="INBOX", update_session=True): if update_session: navparams.store() mbox = navparams.get('mbox') - lst = ImapListing( - request.user, request.session["password"], - baseurl="?action=listmailbox&mbox=%s&" % mbox, - folder=mbox, - elems_per_page=int(parameters.get_user(request.user, "MESSAGES_PER_PAGE")), - **request.session["webmail_navparams"] - ) page_id = int(navparams["page"]) - page = lst.paginator.getpage(page_id) + mbc = get_imapconnector(request) + mbc.parse_search_parameters( + navparams.get("criteria"), navparams.get("pattern")) + + paginator = Paginator( + mbc.messages_count(folder=mbox, order=navparams.get("order")), + int(parameters.get_user(request.user, "MESSAGES_PER_PAGE")) + ) + page = paginator.getpage(page_id) + if page is not None: - email_list = lst.mbc.fetch( - page.id_start, page.id_stop, mbox, - nbelems=int(parameters.get_user(request.user, "MESSAGES_PER_PAGE")) + email_list = mbc.fetch( + page.id_start, page.id_stop, mbox, nbelems=page.items ) content = _render_to_string(request, "webmail/email_list.html", { "email_list": email_list, "page": page_id, "with_top_div": request.GET.get("scroll", "false") == "false" }) + length = len(content) else: - content = "" + content = "
{}
".format( + _("Empty mailbox") + ) + length = 0 navparams["page"] = previous_page_id - return {"listing": content, "length": len(content), "page": page_id} - #return lst.render(request, navparams.get('page')) + return {"listing": content, "length": length, "page": page_id} def render_compose(request, form, posturl, email=None, insert_signature=False): @@ -513,8 +519,11 @@ def viewmail(request): @login_required @needs_mailbox() def submailboxes(request): + """Retrieve the sub mailboxes of a mailbox.""" topmailbox = request.GET.get('topmailbox', '') - mboxes = get_imapconnector(request).getmboxes(request.user, topmailbox) + with_unseen = request.GET.get('unseen', None) + mboxes = get_imapconnector(request).getmboxes( + request.user, topmailbox, unseen_messages=with_unseen == 'true') return render_to_json_response(mboxes) @@ -575,7 +584,7 @@ def index(request): imapc.getquota(curmbox) response["refreshrate"] = \ int(parameters.get_user(request.user, "REFRESH_INTERVAL")) - response["quota"] = ImapListing.computequota(imapc) + response["quota"] = imapc.quota_usage trash = parameters.get_user(request.user, "TRASH_FOLDER") response["trash"] = trash response["ro_mboxes"] = [ diff --git a/modoboa/lib/email_listing.py b/modoboa/lib/email_listing.py index 8d4c6e904..a576129df 100644 --- a/modoboa/lib/email_listing.py +++ b/modoboa/lib/email_listing.py @@ -4,72 +4,7 @@ from django.template.loader import render_to_string from django.template import Template, Context from django.utils.translation import ugettext as _ -attached_map = {} - - -class Page(object): - def __init__(self, pageid, id_start, id_stop, items, - items_per_page, has_previous, has_next, - baseurl=None): - self.number = pageid - self.id_start = id_start - self.id_stop = id_stop - self.items = items - self.items_per_page = items_per_page - self.has_previous = has_previous - self.has_next = has_next - self.baseurl = baseurl - - def previous_page_number(self): - if not self.has_previous: - return False - return self.number - 1 - - def next_page_number(self): - if not self.has_next: - return False - return self.number + 1 - - def last_page(self): - lid = self.items / self.items_per_page - if not lid: - return 1 - if self.items % self.items_per_page: - lid += 1 - return lid - - -class Paginator(object): - def __init__(self, total, elems_per_page): - self.total = total - self.elems_per_page = elems_per_page - self.num_pages = total / elems_per_page - if total % elems_per_page: - self.num_pages += 1 - - def _indexes(self, page): - id_start = self.elems_per_page * page + 1 - id_stop = id_start + self.elems_per_page - 1 - return (id_start, id_stop) - - def getpage(self, page): - if page < 1: - return None - id_start, id_stop = self._indexes(page - 1) - has_previous = has_next = False - if id_start <= self.total: - if page > 1: - has_previous = True - if id_stop < self.total: - has_next = True - else: - id_stop = self.total - else: - return None - p = Page(page, id_start, id_stop, self.total, - self.elems_per_page, has_previous, has_next) - p.paginator = self - return p +from modoboa.lib.paginator import Paginator class EmailListing(object): diff --git a/modoboa/lib/paginator.py b/modoboa/lib/paginator.py new file mode 100644 index 000000000..6ba5dab20 --- /dev/null +++ b/modoboa/lib/paginator.py @@ -0,0 +1,99 @@ +""" +Custom pagination tools. +""" + + +class Page(object): + + """Class to represent a page.""" + + def __init__(self, paginator, pageid, id_start, id_stop, baseurl=None): + """Constructor.""" + self.paginator = paginator + self.number = pageid + self.id_start = id_start + self.id_stop = id_stop + self.baseurl = baseurl + + self._has_previous = None + self._has_next = None + + @property + def items_per_page(self): + """The number of items in a page. (shortcut)""" + return self.paginator.elems_per_page + + @property + def items(self): + """The total number of items. (shortcut)""" + return self.paginator.total + + @property + def has_previous(self): + """Tell if a previous page is available or not.""" + if self._has_previous is None: + self._has_previous = True if self.number > 1 else False + return self._has_previous + + @property + def previous_page_number(self): + """Return the index of the previous page.""" + if not self.has_previous: + return False + return self.number - 1 + + @property + def has_next(self): + """Tell if a next page is available or not.""" + if self._has_next is None: + self._has_next = ( + True if self.id_stop < self.paginator.total else False + ) + return self._has_next + + @property + def next_page_number(self): + """Return the index of the next page.""" + if not self.has_next: + return False + return self.number + 1 + + @property + def last_page(self): + """Retrieve the id of the last page.""" + lid = self.items / self.items_per_page + if not lid: + return 1 + if self.items % self.items_per_page: + lid += 1 + return lid + + +class Paginator(object): + + """Pagination class.""" + + def __init__(self, total, elems_per_page): + self.total = total + self.elems_per_page = elems_per_page + self.num_pages = total / elems_per_page + if total % elems_per_page: + self.num_pages += 1 + + def _indexes(self, page): + """Compute start and stop indexes.""" + id_start = self.elems_per_page * page + 1 + id_stop = id_start + self.elems_per_page - 1 + return (id_start, id_stop) + + def getpage(self, page_id): + """Retrieve a specific page.""" + if page_id < 1: + return None + id_start, id_stop = self._indexes(page_id - 1) + if id_start <= self.total: + if id_stop >= self.total: + id_stop = self.total + else: + return None + return Page(self, page_id, id_start, id_stop) diff --git a/modoboa/static/js/global.js b/modoboa/static/js/global.js index 30a49dba9..f13dc6343 100644 --- a/modoboa/static/js/global.js +++ b/modoboa/static/js/global.js @@ -20,6 +20,11 @@ function get_static_url(value) { return static_url + value; } +/** + * Open a modal box and load its content using an AJAX request. + * + * @param {Object} e - event object + */ function modalbox(e, css, defhref, defcb, defclosecb) { e.preventDefault(); var $this = $(this); @@ -39,7 +44,8 @@ function modalbox(e, css, defhref, defcb, defclosecb) { url: href }).done(function(data) { var $div = $('
', { - id: "modalbox", 'class': "modal fade", html: data + id: "modalbox", 'class': "modal fade", role: "modal", + html: data, 'aria-hidden': true }); $div.modal({show: false}); diff --git a/modoboa/static/js/jquery.infinitescroll.js b/modoboa/static/js/jquery.infinitescroll.js index e577b09b2..80f0fc43a 100644 --- a/modoboa/static/js/jquery.infinitescroll.js +++ b/modoboa/static/js/jquery.infinitescroll.js @@ -10,7 +10,7 @@ * Creates an instance of InfiniteScroll. * * @constructor - * @this {InfiniteScroll} + * @this InfiniteScroll * @param {object} element * @param {dictionary} options - instance options */ @@ -33,7 +33,7 @@ /** * Scroll event handler. * - * @this {InfiniteScroll} + * @this InfiniteScroll */ on_scroll: function() { var bottom = this.$options.calculate_bottom(this.$element); @@ -49,7 +49,7 @@ * Load the previous page from the server. * * @private - * @this {InfiniteScroll} + * @this InfiniteScroll */ load_previous_page: function() { var $this = this; @@ -74,7 +74,7 @@ /** * Load the next page from the server. * - * @this {InfiniteScroll} + * @this InfiniteScroll */ load_next_page: function() { var $this = this; @@ -95,7 +95,7 @@ * Load a page's content. * * @private - * @this {InfiniteScroll} + * @this InfiniteScroll * @param {string} direction - direction of the scroll (up or down) */ load_page: function(direction) { @@ -117,7 +117,6 @@ } $this.executing = false; $this.loaded_pages.push($this.current_page); - console.log("page", $this.current_page, "loaded successfuly"); } }); }, @@ -125,18 +124,19 @@ /** * Reset the loaded pages cache. * - * @this {InfiniteScroll} + * @this InfiniteScroll * @param {Array} current_page - the new current_page */ reset_loaded_pages: function(current_page) { this.current_page = current_page; this.loaded_pages = [this.current_page]; + this.end_of_results = false; }, /** * Suspend the "infinite scroll" mode. * - * @this {InfiniteScroll} + * @this InfiniteScroll */ pause: function() { this.$element.unbind("scroll"); @@ -145,7 +145,7 @@ /** * Resume the "infinite scroll" mode. * - * @this {InfiniteScroll} + * @this InfiniteScroll */ resume: function() { this.$element.scroll($.proxy(this.on_scroll, this)); diff --git a/modoboa/static/js/searchbar.js b/modoboa/static/js/searchbar.js index d4734523f..10d163337 100644 --- a/modoboa/static/js/searchbar.js +++ b/modoboa/static/js/searchbar.js @@ -1,4 +1,12 @@ (function($) { + + /** + * Return an instance of SearchBar. + * + * @constructor + * @param {Object} element - + * @param {Object} options - instance options + */ var SearchBar = function(element, options) { this.initialize(element, options); }; @@ -16,24 +24,30 @@ }); this.$element.blur(function(e) { var $this = $(this); - if ($this.val() == "") { + if ($this.val() === "") { $this.val(gettext("Search...")); } }); - if (this.options.navobj.params.pattern != undefined) { + if (this.options.navobj.params.pattern !== undefined) { this.$element.val(this.options.navobj.getparam("pattern")); } - if (this.options.navobj.params.criteria != undefined) { + if (this.options.navobj.params.criteria !== undefined) { $("#crit_" + this.options.navobj.params.criteria).attr("checked", "checked"); } }, + /** + * Change event: apply search criterion. + * + * @this SearchBar + * @param {Object} e - event object + */ pattern_change: function(e) { var $input = $(e.target); var criteria = $("input[name=scriteria]:checked").val(); var pattern = $input.val(); - if (pattern != "") { + if (pattern !== "") { this.options.navobj.setparams({ pattern: pattern, criteria: criteria @@ -43,6 +57,9 @@ this.options.navobj.delparam("criteria"); this.options.navobj.delparam("page"); } + if (this.options.pattern_changed) { + this.options.pattern_changed(this.options.navobj); + } this.options.navobj.update(); } }; @@ -63,6 +80,7 @@ }; $.fn.searchbar.defaults = { - navobj: null + navobj: null, + pattern_changed: null }; -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/modoboa/templates/common/generic_modal.html b/modoboa/templates/common/generic_modal.html index 23a890ca7..b0a389b0a 100644 --- a/modoboa/templates/common/generic_modal.html +++ b/modoboa/templates/common/generic_modal.html @@ -1,6 +1,6 @@ {% load i18n %} -