diff --git a/doc/conf.py b/doc/conf.py index 212ac06d9..1eec437de 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -91,7 +91,7 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = 'nature' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/extensions/webmail/lib.py b/extensions/webmail/lib.py index c5353aacd..2f31177f0 100644 --- a/extensions/webmail/lib.py +++ b/extensions/webmail/lib.py @@ -317,6 +317,13 @@ class IMAPconnector(object): return False return True + def rename_folder(self, oldname, newname): + typ, data = self.m.rename(self._encodefolder(oldname), + self._encodefolder(newname)) + if typ == "NO": + return False + return True + def delete_folder(self, name): typ, data = self.m.delete(self._encodefolder(name)) if typ == "NO": diff --git a/extensions/webmail/static/css/folders.css b/extensions/webmail/static/css/folders.css index 796f50419..14511c42f 100644 --- a/extensions/webmail/static/css/folders.css +++ b/extensions/webmail/static/css/folders.css @@ -31,13 +31,19 @@ .box ul { list-style: none; - padding: 5px 5px; + padding: 0 0 0 5px; margin: 0; + background-color: #FFFFFF; +} + +.box li ul { + padding: 0 0 0 8px; } .box li { - margin-bottom: 4px; - padding-left: 15px; + margin: 0; + background-position: 2px 2px; + position: relative; } .box li.selected { @@ -45,10 +51,13 @@ } .box a:link, .box a:visited { - background: transparent; color: black; text-decoration: none; - margin-left: 5px; +} + +a.block { + display: block; + padding: 2px 10px 2px 30px; } .box a:hover { @@ -69,24 +78,29 @@ img.aligned { } img.footer { - float: none; - vertical-align: bottom; + float: left; + margin-top: 10px; + margin-left: 18px; } li.inbox { - background: url("/static/pics/overview.png") no-repeat; + background-image: url("/static/pics/overview.png"); + background-repeat: no-repeat; } li.trash { - background: url("/static/pics/trash.png") no-repeat; + background-image: url("/static/pics/trash.png"); + background-repeat: no-repeat; } li.folder { - background: url("/static/pics/folder.png") no-repeat; + background-image: url("/static/pics/folder.png"); + background-repeat: no-repeat; } li.subfolders { - background: url("/static/pics/subfolders.png") no-repeat; + background-image: url("/static/pics/folder.png"); + background-repeat: no-repeat; } ul.hidden { @@ -96,4 +110,22 @@ ul.hidden { ul.visible { display: block; padding-bottom: 0; +} + +div.clickbox { + position: absolute; + left: 2px; + 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; } \ No newline at end of file diff --git a/extensions/webmail/static/css/webmail.css b/extensions/webmail/static/css/webmail.css index 1928e05ac..19acbfa47 100644 --- a/extensions/webmail/static/css/webmail.css +++ b/extensions/webmail/static/css/webmail.css @@ -157,7 +157,6 @@ textarea:hover { float: left; } -/* context menu specific */ #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; } diff --git a/extensions/webmail/static/js/fdmenu.js b/extensions/webmail/static/js/fdmenu.js index 2c540cae9..f178aa404 100644 --- a/extensions/webmail/static/js/fdmenu.js +++ b/extensions/webmail/static/js/fdmenu.js @@ -6,18 +6,17 @@ var FdMenu = new Class({ Implements: [Options], options: { - media_url: "", modify_url: "", delete_url: "" }, add_entry: function(name, label, pic, url, onclick) { var item = new Element("li"); - var picpath = this.options.media_url + "pics/" + pic; + var picpath = static_url("pics/" + pic); this[name] = new Element("a") .set("html", " " + label) - .addEvent("click", onclick) + .addEvent("click", onclick.bind(this)) .inject(item); item.inject(this.list); }, @@ -36,28 +35,36 @@ var FdMenu = new Class({ size: {x: 350, y: 400}, handler: 'iframe' }); - SqueezeBox.open(this.get("href")); + SqueezeBox.open(evt.target.get("href")); + $(document.body).fireEvent("click"); }); this.add_entry("delbutton", gettext("Delete folder"), "remove.png", - this.options.delete_url, function(evt) { - evt.stop(); - if (!confirm(gettext("Delete folder?"))) { - return; - } - new Request.JSON({ - url: this.get("href"), - method: "GET", - onSuccess: function(resp) { - if (resp.status == "ok") { - infobox.info(gettext("Folder deleted.")); - var id = current_anchor.update.delay(500, current_anchor, 1); - } else { - infobox.error(gettext("Failed to delete folder")); - infobox.hide(2); - } - } - }).send(); - }); + this.options.delete_url, function(evt) { + evt.stop(); + $(document.body).fireEvent("click"); + if (!confirm(gettext("Delete folder?"))) { + return; + } + new Request.JSON({ + url: evt.target.get("href"), + method: "GET", + onSuccess: function(resp) { + if (resp.status == "ok") { + var dfolder = this.current_folder + "/"; + infobox.info(gettext("Folder deleted.")); + if (dfolder == current_anchor.base) { + var pfolder = ((this.current_folder.split(".")).slice(0, -1)).join("."); + current_anchor.baseurl(pfolder, 1); + } + current_anchor.update.delay(500, current_anchor, 1); + } else { + infobox.error(gettext("Failed to delete folder")); + infobox.hide(2); + } + }.bind(this) + }).send(); + } + ); this.list.inject(this.container); this.shown = false; @@ -80,7 +87,9 @@ var FdMenu = new Class({ }); 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() { diff --git a/extensions/webmail/static/js/webmail.js b/extensions/webmail/static/js/webmail.js new file mode 100644 index 000000000..9df19f5a4 --- /dev/null +++ b/extensions/webmail/static/js/webmail.js @@ -0,0 +1,227 @@ +/* + * Globals + */ +var rtimer = null; + +/* + * Enables folders opening/closing + * + * Available for folders with subfolders. + */ +function init_folders_browsing() { + $$("div[class*=clickbox]").addEvent("click", function(evt) { + var parent = this.getParent(); + var ul = parent.getFirst("ul[name=" + parent.get("name") + "]"); + + if (!$defined(ul)) { + return; + } + if (ul.hasClass("hidden")) { + this.removeClass("collapsed").addClass("expanded"); + ul.removeClass("hidden").addClass("visible"); + } else { + this.removeClass("expanded").addClass("collapsed"); + ul.removeClass("visible").addClass("hidden"); + } + evt.stop(); + }); +} + +/* + * Select a particular folder + */ +function select_folder(obj) { + $$("a[name=loadfolder]").each(function(item) { + item.getParent().removeClass("selected"); + item.getParent().addClass("droppable"); + }); + obj.getParent().removeClass("droppable"); + obj.getParent().addClass("selected"); + + $$(obj.getParents("ul[class*=hidden]")).each(function(item) { + item.removeClass("hidden"); + item.addClass("visible"); + $$("li[name=" + item.get("name") + "]").each(function(item) { + item.setStyle("background", + "url('" + static_url("pics/folder-open.png") + "') no-repeat"); + }); + }); +} + +/* + * Callback of the 'viewmail' action + */ +function viewmail_cb(resp) { + wm_updatelisting(resp, "hidden"); + $$("a[name=back]").addEvent("click", loadFolder); + $$("a[name=reply]").addEvent("click", reply_loader); + $$("a[name=replyall]").addEvent("click", replyall_loader); + $$("a[name=forward]").addEvent("click", forward_loader); + $$("a[name=delete]").addEvent("click", function(event) { + var lnk = event.target; + + event.stop(); + new Request.JSON({ + url: lnk.get("href"), onSuccess: function(resp) { + current_anchor.parse_string(resp.next).update(); + select_folder($$("a[href=" + current_anchor.getbaseurl() + "]")); + } + }).get(); + }); + $$("a[name=activate_links]").addEvent("click", function(evt) { + evt.stop(); + current_anchor.setparam("links", "1").update(); + }); + $$("a[name=disable_links]").addEvent("click", function(evt) { + evt.stop(); + current_anchor.setparam("links", "0").update(); + }); + setDivHeight("mailcontent", 5, 0); +} + +/* + * Loader of the 'compose' action (called when the associated button + * is clicked) + */ +function compose_loader(event) { + event.stop(); + current_anchor.baseurl("compose").update(); +} + +/* + * Callback of the 'compose' action + */ +function compose_callback(resp) { + wm_updatelisting(resp); + window.addEvent("resize", function(evt) { + setDivHeight("id_body", $("mailheader").getSize().y, 0); + }); + window.fireEvent("resize"); + + var editormode = resp.editor; + var editorid = "id_body"; + + if (editormode == "html") { + var instance = CKEDITOR.instances[editorid]; + if (instance) { + CKEDITOR.remove(instance); + } + CKEDITOR.replace(editorid, { + customConfig: static_url("js/editor_config.js"), + height: $(editorid).getSize().y + }); + } + $$("a[name=back]").addEvent("click", loadFolder); + $$("a[name=sendmail]").addEvent("click", function(evt) { + evt.stop(); + $("composemail").set("send", { + onSuccess: function(resp) { + resp = JSON.decode(resp); + if (resp.status == "ko") { + wm_updatelisting(resp); + window.fireEvent("resize"); + if ($defined(resp.error)) { + infobox.error(resp.error); + } + return; + } + current_anchor.parse_string(resp.url, true).setparams(navparams); + current_anchor.update(); + } + }); + if (editormode == "html") { + CKEDITOR.instances[editorid].updateElement(); + } + $("composemail").send(); + }); +} + +/* + * Loader of the 'reply' action (called when the associated button + * is clicked). + */ +function reply_loader(event) { + event.stop(); + location.hash += event.target.get("href"); +} + +/* + * Loader of the 'replyall' action (called when the associated button + * is clicked). + */ +function replyall_loader(event) { + event.stop(); + location.hash += event.target.get("href") + "?all=1"; +} + +/* + * Loader of the 'forward' action (called when the associated button + * is clicked). + */ +function forward_loader(event) { + event.stop(); + location.hash += event.target.get("href"); +} + +/* + * Onclick callback used to load the content of a particular + * folder. (activated when clicking on a folder's name) + */ +function loadFolder(event, obj) { + event.stop(); + if (!$defined(obj)) { + obj = $(event.target); + } + current_anchor.parse_string(gethref(obj), true).setparams(navparams); + current_anchor.update(); +} + +function foldercallback(event) { + select_folder(event.target); + loadFolder(event, event.target); +} + +/* + * Automatic folder listing refresh + * + * Called at a regular frequency to make an asynchronous request that + * retrieves a folder's content (ie. mails) + */ +function refreshFolder() { + var query = current_anchor.serialized.substring(1); + + clearInterval(rtimer); + infobox.show(gettext("Reloading..."), { + profile : "gray", + spinner : true + }); + new Request.JSON({url: query, noCache : true, onSuccess: function(resp) { + var callback = ($defined(resp.callback)) ? resp.callback : "default"; + + callbacks[callback](resp); + infobox.info(gettext("Done")); + infobox.hide(1); + }}).get(); +} + +/* + * Simple AJAX request + * + * Initialize the infobox with a loading message and wait for a JSON + * encoded answer. The infobox is cleared by the request callback + * function. + */ +function simple_request(url, params) { + infobox.show(gettext("Waiting..."), { + profile: "gray", + spinner: true + }); + new Request.JSON({ + url : url, + onSuccess : function(response) { + get_callback("folder")(response); + infobox.info(gettext("Done")); + infobox.hide(1); + } + }).get(params); +} \ No newline at end of file diff --git a/extensions/webmail/templates/webmail/folder.html b/extensions/webmail/templates/webmail/folder.html index 59d0f3492..912fc79a1 100644 --- a/extensions/webmail/templates/webmail/folder.html +++ b/extensions/webmail/templates/webmail/folder.html @@ -3,24 +3,11 @@ {% block html_head %} + + +{{ block.super }} + {% endblock %} {% block js %} quota_pb = new ProgressBar({ @@ -14,168 +57,12 @@ displayID: "quotatext" }); - wm_updatelisting = function(resp) { - window.removeEvents("resize"); - updatelisting(resp); - if ($defined(resp.folders)) { - $("folders").set("html", resp.folders); - $$("li[class*=clickable]").removeEvents(); - SqueezeBox.assign($$('a[class=boxed]'), { - parse: 'rel' - }); - - var fdbuttons = $$("img[class*=footer]"); - var fdmenu = new FdMenu({ - media_url: "{{MEDIA_URL}}", - modify_url: "{% url extensions.webmail.views.editfolder %}", - delete_url: "{% url extensions.webmail.views.delfolder %}" - }); - - fdbuttons.addEvents({ - click: function(evt) { - var parent = this.getParent(); - var fdname = parent.getFirst("a[name=loadfolder]").get("href"); - - fdmenu.toggle(this, fdname); - evt.stop(); - } - }); - } - select($$("a[href=" + current_anchor.getbaseurl() + "]")); - $$("li[class*=clickable]").addEvent("click", function(evt) { - $$("ul[name=" + evt.target.get("name") + "]").each(function(item) { - if (item.hasClass("hidden")) { - evt.target.setStyle("background", - "url('{{ MEDIA_URL }}pics/folder-open.png') no-repeat"); - item.removeClass("hidden").addClass("visible"); - } else { - evt.target.setStyle("background", - "url('{{ MEDIA_URL }}pics/subfolders.png') no-repeat"); - item.removeClass("visible").addClass("hidden"); - } - }); - evt.stop(); - }); - if ($defined(resp.quota) && resp.quota != "-1") { - quota_pb.set(resp.quota); - $("quotabox").setStyle("display", "block"); - $("quotalabel").setStyle("display", "block"); - } - $$("a[name=loadfolder]").addEvent("click", foldercallback); - $$("a[name=compose]").addEvent("click", loadCompose); - }; - - select = function(obj) { - $$("a[name=loadfolder]").each(function(item) { - item.getParent().removeClass("selected"); - item.getParent().addClass("droppable"); - }); - obj.getParent().removeClass("droppable"); - obj.getParent().addClass("selected"); - - $$(obj.getParents("ul[class*=hidden]")).each(function(item) { - item.removeClass("hidden"); - item.addClass("visible"); - $$("li[name=" + item.get("name") + "]").each(function(item) { - item.setStyle("background", "url('{{ MEDIA_URL }}pics/folder-open.png') no-repeat"); - }); - }); - }; - - register_callback("viewmail", function(resp) { - wm_updatelisting(resp, "hidden"); - $$("a[name=back]").addEvent("click", loadFolder); - $$("a[name=reply]").addEvent("click", reply); - $$("a[name=replyall]").addEvent("click", replyall); - $$("a[name=forward]").addEvent("click", forward); - $$("a[name=delete]").addEvent("click", function(event) { - var lnk = event.target; - - event.stop(); - new Request.JSON({url: lnk.get("href"), onSuccess: function(resp) { - current_anchor.parse_string(resp.next).update(); - select($$("a[href=" + current_anchor.getbaseurl() + "]")); - }}).get(); - }); - $$("a[name=activate_links]").addEvent("click", function(evt) { - evt.stop(); - current_anchor.setparam("links", "1").update(); - }); - $$("a[name=disable_links]").addEvent("click", function(evt) { - evt.stop(); - current_anchor.setparam("links", "0").update(); - }); - setDivHeight("mailcontent", 5, 0); - }); - - compose_callback = function(resp) { - wm_updatelisting(resp); - window.addEvent("resize", function(evt) { - setDivHeight("id_body", $("mailheader").getSize().y, 0); - }); - window.fireEvent("resize"); - - var editormode = resp.editor; - var editorid = "id_body"; - if (editormode == "html") { - var instance = CKEDITOR.instances[editorid]; - if (instance) { - CKEDITOR.remove(instance); - } - CKEDITOR.replace(editorid, { - customConfig: "{{ MEDIA_URL }}/js/editor_config.js", - height: $(editorid).getSize().y - }); - } - $$("a[name=back]").addEvent("click", loadFolder); - $$("a[name=sendmail]").addEvent("click", function(evt) { - evt.stop(); - $("composemail").set("send", { - onSuccess: function(resp) { - resp = JSON.decode(resp); - if (resp.status == "ko") { - wm_updatelisting(resp); - window.fireEvent("resize"); - if ($defined(resp.error)) { - infobox.error(resp.error); - } - return; - } - current_anchor.parse_string(resp.url, true).setparams(navparams); - current_anchor.update(); - } - }); - if (editormode == "html") { - CKEDITOR.instances[editorid].updateElement(); - } - $("composemail").send(); - }); - }; - - loadCompose = function(event) { - event.stop(); - current_anchor.baseurl("compose").update(); - }; + register_callback("viewmail", viewmail_cb); register_callback("compose", compose_callback); - - reply = function(event) { - event.stop(); - location.hash += event.target.get("href"); - }; register_callback("reply", compose_callback); - replyall = function(event) { - event.stop(); - location.hash += event.target.get("href") + "?all=1"; - }; register_callback("replyall", compose_callback); - forward = function(event) { - event.stop(); - location.hash += event.target.get("href"); - }; register_callback("forward", compose_callback); - var rtimer = null; - window.addEvent("pageRefresh", function() { if (rtimer) { clearInterval(rtimer); @@ -183,30 +70,6 @@ } }); - refreshFolder = function() { - var query = current_anchor.serialized.substring(1); - clearInterval(rtimer); - infobox.show('{% trans "Reloading..." %}', { - profile : "gray", - spinner : true - }); - new Request.JSON({url: query, noCache : true, onSuccess: function(resp) { - callback = ($defined(resp.callback)) ? resp.callback : "default"; - callbacks[callback](resp); - infobox.info('{% trans "Done" %}'); - infobox.hide(1); - }}).get(); - }; - - loadFolder = function(event, obj) { - event.stop(); - if (!$defined(obj)) { - obj = $(event.target); - } - current_anchor.parse_string(gethref(obj), true).setparams(navparams); - current_anchor.update(); - }; - register_callback("folder", function(resp) { wm_updatelisting(resp); rtimer = refreshFolder.periodical({{ refreshrate }}); @@ -214,7 +77,7 @@ if (navparams.has("order")) { src = navparams.get("order").charAt(0) == "-" ? "down_arrow.png" : "up_arrow.png"; th = $$("th[id=" + navparams.get("order").substring(1) + "]"); - th.getElement("img").set("src", "{{ MEDIA_URL }}pics/" + src); + th.getElement("img").set("src", static_url("pics/" + src)); th.getElement("img").setStyle("display", "block"); th.addClass("selected"); } @@ -319,20 +182,6 @@ }); }); - simple_request = function(url, params) { - infobox.show(gettext("Waiting..."), { - profile: "gray", - spinner: true - }); - new Request.JSON({url : url, - onSuccess : function(response) { - get_callback("folder")(response); - infobox.info(gettext("Done")); - infobox.hide(1); - } - }).get(params); - }; - buildmarkrequest = function(evt) { evt.stop(); if (!selectedRows.length) { @@ -380,12 +229,6 @@ current_anchor.setparams(navparams).update(); }); }); - - foldercallback = function(event) { - select(event.target); - loadFolder(event, event.target); - }; - {% endblock %} {% block middletitle %}{% trans "Webmail" %}{% endblock %} {% block leftcol %} diff --git a/extensions/webmail/templatetags/webextras.py b/extensions/webmail/templatetags/webextras.py index 782760d43..92feb0a69 100644 --- a/extensions/webmail/templatetags/webextras.py +++ b/extensions/webmail/templatetags/webextras.py @@ -119,34 +119,33 @@ def listing_menu(selection, folder, user): def print_folders(folders, selected=None, withunseen=False, withmenu=False): result = "" - import pprint - pprint.PrettyPrinter(indent=2).pprint(folders) - print "END" - - for fd in folders: - if fd.has_key("class"): - cssclass = fd["class"] - else: - cssclass = "folder" - name = "" - if fd.has_key("sub"): - cssclass += " clickable" - name = fd["path"] + cssclass = fd["class"] if fd.has_key("class") else "folder" + name = fd["path"] if fd.has_key("sub") else fd["name"] label = fd["name"] - if selected == label: + if selected == name: cssclass += " selected" result += "
  • \n" % (name, cssclass) + if fd.has_key("sub") and len(fd["sub"]): + if selected is not None and selected != name and selected.count(name): + ul_state = "visible" + div_state = "expanded" + else: + ul_state = "hidden" + div_state = "collapsed" + result += "
     
    " % div_state if withmenu: - result += "" % settings.MEDIA_URL - - cssclass = "" + result += "" \ + % settings.MEDIA_URL + + cssclass = "block" if withunseen and fd.has_key("unseen"): label += " (%d)" % fd["unseen"] - cssclass = "unseen" + cssclass += " unseen" result += "%s\n" \ % (fd.has_key("path") and fd["path"] or fd["name"], cssclass, label) if fd.has_key("sub") and len(fd["sub"]): - result += "\n" + result += "\n" result += "
  • \n" return result diff --git a/extensions/webmail/views.py b/extensions/webmail/views.py index 9a5eded9a..e7634e559 100644 --- a/extensions/webmail/views.py +++ b/extensions/webmail/views.py @@ -428,6 +428,19 @@ def forward(request, folder, mail_id): return render_compose(request, form, reverse(forward, args=[folder, mail_id]), email) +def separate_folder(fullname, sep="."): + """Split a folder name + + If a separator is found in fullname, this function returns the + corresponding name and parent folder name. + """ + if fullname.count("."): + parts = fullname.split(sep) + name = parts[-1] + parent = sep.join(parts[0:len(parts) - 1]) + return name, parent + return fullname, None + @login_required @is_not_localadmin() def newfolder(request, tplname="webmail/folder.html"): @@ -466,19 +479,35 @@ def editfolder(request, tplname="webmail/folder.html"): "withmenu" : False, "withunseen" : False} ctx["folders"] = mbc.getfolders(request.user) + if request.method == "POST": + form = FolderForm(request.POST) + if form.is_valid(): + pf = request.POST.has_key("parent_folder") \ + and request.POST["parent_folder"] or None + ctx["selected"] = pf + oldname, oldparent = separate_folder(request.POST["oldname"]) + try: + extra = {} + if form.cleaned_data["name"] != oldname \ + or (pf is not None and pf != oldparent): + newname = form.cleaned_data["name"] if pf is None \ + else "%s.%s" % (pf, form.cleaned_data["name"]) + if not mbc.rename_folder(request.POST["oldname"], newname): + raise Exception + extra["url"] = newname + return ajax_response(request, ajaxnav=True, **extra) + except Exception: + pass + ctx["form"] = form + return ajax_response(request, status="ko", template=tplname, **ctx) + if not request.GET.has_key("name") or request.GET["name"] == "": return name = request.GET["name"] - if name.count("."): - parts = name.split(".") - name = parts[-1] - parent = ".".join(parts[0:len(parts) - 1]) - else: - parent = None - print parent + ctx["oldname"] = name + name, parent = separate_folder(name) ctx["form"] = FolderForm() ctx["form"].fields["name"].initial = name - parts = request ctx["selected"] = parent return _render(request, tplname, ctx) diff --git a/lib/__init__.py b/lib/__init__.py index 0a9586e9c..352cdb9ba 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -97,7 +97,7 @@ def ajax_response(request, status="ok", url="", ajaxnav=False, template=None, ** jsonctx = {"status" : status, "content" : content} if ajaxnav: jsonctx["ajaxnav"] = True - else: + if url != "": jsonctx["url"] = url return HttpResponse(simplejson.dumps(jsonctx), mimetype="application/json") diff --git a/static/js/common.js b/static/js/common.js index c8d5d6007..e85f4d928 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -8,9 +8,26 @@ window.addEvent('domready', function(){ }); }); +var media_url = ""; callbacks = {}; -register_callback = function(name, callback) { +/* + * A simple function to initialize the value of the global variable + * 'media_url' (corresponding to django's MEDIA_URL variable). + */ +function set_media_url(url) { + media_url = url; +} + +/* + * Shortcut function that construct an url from the media_url and the + * given value. + */ +function static_url(value) { + return media_url + value; +} + +function register_callback(name, callback) { callbacks[name] = callback; }; @@ -18,170 +35,177 @@ get_callback = function(name) { return callbacks[name]; }; -current_anchor = null; +/* + * AJAX anchor based navigation + */ +var current_anchor = null; -check_anchor = function() { - if (current_anchor.serialized == location.hash - && !$defined(current_anchor.force)) { - return; - } - delete(current_anchor.force); - current_anchor.from_string(location.hash); - if (!current_anchor.serialized) { - location.hash = current_anchor.deflocation; - return; - } else { - query = current_anchor.serialized.substring(1); - } - infobox.show(gettext("Loading..."), { - profile: "gray", - spinner: true - }); - new Request.JSON({url: query, noCache : true, onSuccess: function(resp) { - var callback = ($defined(resp.callback)) ? resp.callback : "default"; - callbacks[callback](resp); - infobox.info(gettext("Done")); - infobox.hide(1); - }}).get(); -}; +function check_anchor() { + if (current_anchor.serialized == location.hash + && !$defined(current_anchor.force)) { + return; + } + delete(current_anchor.force); + current_anchor.from_string(location.hash); + if (!current_anchor.serialized) { + location.hash = current_anchor.deflocation; + return; + } -ajaxListener = function(deflocation, defcallback) { - current_anchor = new HashWrapper(deflocation); - register_callback("default", defcallback); - check_anchor.periodical(300); + var query = current_anchor.serialized.substring(1); + + infobox.show(gettext("Loading..."), { + profile: "gray", + spinner: true + }); + new Request.JSON({url: query, noCache : true, onSuccess: function(resp) { + var callback = ($defined(resp.callback)) ? resp.callback : "default"; + callbacks[callback](resp); + infobox.info(gettext("Done")); + infobox.hide(1); + }}).get(); }; /* -* -*/ + * Initialize the AJAX anchor based navigation + */ +function ajaxListener(deflocation, defcallback) { + current_anchor = new HashWrapper(deflocation); + register_callback("default", defcallback); + check_anchor.periodical(300); +}; + +/* + * + */ function HashWrapper(deflocation) { - this.deflocation = deflocation; - this.params = $H(); - this.base = ''; - this.serialized = null; + this.deflocation = deflocation; + this.params = $H(); + this.base = ''; + this.serialized = null; - this.reset = function() { - this.base = null; - this.params.empty(); - return this; - }; + this.reset = function() { + this.base = null; + this.params.empty(); + return this; + }; - this.parse_string = function(value, reset) { - var splits = (value.charAt(0) == '#') - ? value.substring(1).split('?') : value.split('?'); + this.parse_string = function(value, reset) { + var splits = (value.charAt(0) == '#') + ? value.substring(1).split('?') : value.split('?'); - if (splits.length == 0) { - return this; - } - if (!$defined(reset)) { - reset = false; - } - if (reset) { - this.reset(); - } - this.base = (splits[0] == "") ? this.deflocation : splits[0]; - /*if (this.base[this.base.length - 1] != '/') { - this.base += '/'; - }*/ - var re = new RegExp("/$"); - if (!this.base.match(re)) { - this.base += '/'; - } - if (splits.length > 1) { - params = splits[1].split('&'); - for (var i = 0; i < params.length; i++) { - tmp = params[i].split('='); - this.setparam(tmp[0], tmp[1]); - } - } - return this; - }; + if (splits.length == 0) { + return this; + } + if (!$defined(reset)) { + reset = false; + } + if (reset) { + this.reset(); + } + this.base = (splits[0] == "") ? this.deflocation : splits[0]; - this.from_string = function(value, reset) { - this.parse_string(value); - this.serialized = value; - return this; - }; + var re = new RegExp("/$"); + if (!this.base.match(re)) { + this.base += '/'; + } + if (splits.length > 1) { + var params = splits[1].split('&'); + for (var i = 0; i < params.length; i++) { + var tmp = params[i].split('='); + this.setparam(tmp[0], tmp[1]); + } + } + return this; + }; - this.serialize = function() { - var res = this.base; + this.from_string = function(value, reset) { + this.parse_string(value); + this.serialized = value; + return this; + }; - if (this.params.getLength() != 0) { - res += "?" + this.params.toQueryString(); - } - return res; - }; + this.serialize = function() { + var res = this.base; - this.update = function(force) { - window.fireEvent("pageRefresh"); - location.hash = this.serialize(); - if ($defined(force)) { - this.force = force; - } - }; + if (this.params.getLength() != 0) { + res += "?" + this.params.toQueryString(); + } + return res; + }; - this.deleteParam = function(str) { - this.params.erase(str); - }; + this.update = function(force) { + window.fireEvent("pageRefresh"); + location.hash = this.serialize(); + if ($defined(force)) { + this.force = force; + } + }; - this.updateparams = function(str) { - if (str.charAt(0) == '?') { - str = str.substring(1); - } - var elems = str.split('&'); - for (var i = 0; i < elems.length; i++) { - this.setparamfromstring(elems[i]); - } - }; + this.deleteParam = function(str) { + this.params.erase(str); + }; - this.setparamfromstring = function(str) { - var def = str.split('='); - this.params.set(def[0], def[1]); - }; + this.updateparams = function(str) { + if (str.charAt(0) == '?') { + str = str.substring(1); + } + var elems = str.split('&'); + for (var i = 0; i < elems.length; i++) { + this.setparamfromstring(elems[i]); + } + }; - this.setparam = function(name, value) { - this.params.set(name, value); - return this; - }; + this.setparamfromstring = function(str) { + var def = str.split('='); + this.params.set(def[0], def[1]); + }; - this.setparams = function(params) { - this.params.extend(params); - return this; - }; + this.setparam = function(name, value) { + this.params.set(name, value); + return this; + }; - this.getparam = function(name) { - if (!this.params.has(name)) { - return ""; - } - return this.params.get(name); - }; + this.setparams = function(params) { + this.params.extend(params); + return this; + }; - this.baseurl = function(value) { - this.reset(); - this.base = value; - var re = new RegExp("/$"); - if (!this.base.match(re)) { - this.base += '/'; - } - return this; - }; + this.getparam = function(name) { + if (!this.params.has(name)) { + return ""; + } + return this.params.get(name); + }; - this.addbaseurl = function(value) { - newbase = this.base + value; - return this.baseurl(newbase); - }; + this.baseurl = function(value, noreset) { + if (!$defined(noreset) || noreset == 0) { + this.reset(); + } + this.base = value; + var re = new RegExp("/$"); + if (!this.base.match(re)) { + this.base += '/'; + } + return this; + }; - this.getbaseurl = function() { - return this.base.substr(0, this.base.length - 1); - }; + this.addbaseurl = function(value) { + var newbase = this.base + value; + return this.baseurl(newbase); + }; - this.delparam = function(name) { - if (!this.params.has(name)) { - return false; - } - this.params.erase(name); - return this; - }; + this.getbaseurl = function() { + return this.base.substr(0, this.base.length - 1); + }; + + this.delparam = function(name) { + if (!this.params.has(name)) { + return false; + } + this.params.erase(name); + return this; + }; }; parse_menubar = function(id) { diff --git a/static/js/email_listing.js b/static/js/email_listing.js new file mode 100644 index 000000000..12ab9572c --- /dev/null +++ b/static/js/email_listing.js @@ -0,0 +1,25 @@ +/* + * Shared functions between the webmail and the quarantine plugin. + * + */ + +function navbarcallback(event) { + event.stop(); + current_anchor.setparams(navparams); + current_anchor.parse_string($(event.target).getParent().get("href")).update(); +} + +function updatelisting(resp) { + if ($defined(resp.menu)) { + $("menubar").set("html", resp.menu); + parse_menubar("menubar"); + } + if ($defined(resp.listing)) { + $("listing").set("html", resp.listing); + } + if ($defined(resp.navbar)) { + $("navbar").set("html", resp.navbar); + $("navbar").getChildren("a").addEvent("click", navbarcallback); + } +} + diff --git a/static/js/form.js b/static/js/form.js index 6c4dab943..a3936b17d 100644 --- a/static/js/form.js +++ b/static/js/form.js @@ -34,45 +34,47 @@ function register_extra_data_callback(name, callback) { } function ajax_submit(event) { - var form = event.target; - var myid = form.get("id"); - var data = form.toQueryString(); - - event.stop(); - if ($defined(extra_data_callbacks[myid])) { - if (data != "") { - data += "&"; - } - data += extra_data_callbacks[myid](); - } + var form = event.target; + var myid = form.get("id"); + var data = form.toQueryString(); - new Request({ - method: form.get("method"), - data: data, - onSuccess: function(responseText) { - var response = JSON.decode(responseText); - - if (response.status == "ko") { - $(document.body).set("html", response.content); - $(document.body).addEvent("submit", ajax_submit); - if ($defined(error_callbacks[myid])) { - error_callbacks[myid](); - } - } else { - if ($defined(response.url) && response.url != "") { - parent.location.href = response.url; - } - if ($defined(response.ajaxnav)) { - parent.current_anchor.update(1); - } - parent.SqueezeBox.close(); - } - }, - onFailure: function(xhr) { - parent.document.getElement('iframe').setStyles({width: 800, height: 600}); - $(document.body).set("html", xhr.responseText); + event.stop(); + if ($defined(extra_data_callbacks[myid])) { + if (data != "") { + data += "&"; + } + data += extra_data_callbacks[myid](); + } + + new Request({ + method: form.get("method"), + data: data, + onSuccess: function(responseText) { + var response = JSON.decode(responseText); + + if (response.status == "ko") { + $(document.body).set("html", response.content); + $(document.body).addEvent("submit", ajax_submit); + if ($defined(error_callbacks[myid])) { + error_callbacks[myid](); } - }).send(); + } else { + if ($defined(response.ajaxnav)) { + if ($defined(response.url)) { + parent.current_anchor.baseurl(response.url, 1); + } + parent.current_anchor.update(1); + } else if ($defined(response.url)) { + parent.location.href = response.url; + } + parent.SqueezeBox.close(); + } + }, + onFailure: function(xhr) { + parent.document.getElement('iframe').setStyles({width: 800, height: 600}); + $(document.body).set("html", xhr.responseText); + } + }).send(); } window.addEvent("domready", function() { diff --git a/static/pics/collapsed.png b/static/pics/collapsed.png new file mode 100644 index 000000000..07cc1ec7d Binary files /dev/null and b/static/pics/collapsed.png differ diff --git a/static/pics/expanded.png b/static/pics/expanded.png new file mode 100644 index 000000000..1db079b79 Binary files /dev/null and b/static/pics/expanded.png differ diff --git a/templates/common/email_listing.html b/templates/common/email_listing.html index a4c5c8828..800326063 100644 --- a/templates/common/email_listing.html +++ b/templates/common/email_listing.html @@ -5,7 +5,7 @@ - + {% block css %}{% endblock %} {% url django.views.i18n.javascript_catalog as catalog_url %} - {%block html_head %}{% endblock %} + + {% block html_head %}{% endblock %}