changeset 323:0b7934e75e76

misc: reorganization of the file panels.py + clean the modules import: - some existing modules were not found during JS runtime (panels.py was too large?) - the *Panel classes of panels.py that do not reference "host" have been moved to base_panels.py - cleaned the import in various files
author souliane <souliane@mailoo.org>
date Sat, 04 Jan 2014 00:17:46 +0100
parents 971e3812903a
children 8131d0ccf21b
files browser_side/base_panels.py browser_side/base_widget.py browser_side/contact.py browser_side/dialog.py browser_side/list_manager.py browser_side/panels.py browser_side/richtext.py libervia.py libervia.tac
diffstat 9 files changed, 288 insertions(+), 243 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/browser_side/base_panels.py	Sat Jan 04 00:17:46 2014 +0100
@@ -0,0 +1,247 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+Libervia: a Salut à Toi frontend
+Copyright (C) 2011, 2012, 2013 Jérôme Poisson <goffi@goffi.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import pyjd  # this is dummy in pyjs
+from pyjamas.ui.AbsolutePanel import AbsolutePanel
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.HorizontalPanel import HorizontalPanel
+from pyjamas.ui.HTMLPanel import HTMLPanel
+from pyjamas.ui.Button import Button
+from pyjamas.ui.HTML import HTML
+from pyjamas.ui.PopupPanel import PopupPanel
+from pyjamas.ui.StackPanel import StackPanel
+from pyjamas.ui.Event import BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT
+from pyjamas import DOM
+
+from datetime import datetime
+from time import time
+
+from tools import html_sanitize, inlineRoot
+
+from sat_frontends.tools.strings import addURLToText
+
+
+class ChatText(HTMLPanel):
+
+    def __init__(self, timestamp, nick, mymess, msg, xhtml=None):
+        _date = datetime.fromtimestamp(float(timestamp or time()))
+        _msg_class = ["chat_text_msg"]
+        if mymess:
+            _msg_class.append("chat_text_mymess")
+        HTMLPanel.__init__(self, "<span class='chat_text_timestamp'>%(timestamp)s</span> <span class='chat_text_nick'>%(nick)s</span> <span class='%(msg_class)s'>%(msg)s</span>" %
+                           {"timestamp": _date.strftime("%H:%M"),
+                            "nick": "[%s]" % html_sanitize(nick),
+                            "msg_class": ' '.join(_msg_class),
+                            "msg": addURLToText(html_sanitize(msg)) if not xhtml else inlineRoot(xhtml)}  # FIXME: images and external links must be removed according to preferences
+                           )
+        self.setStyleName('chatText')
+
+
+class Occupant(HTML):
+    """Occupant of a MUC room"""
+
+    def __init__(self, nick, special=""):
+        HTML.__init__(self)
+        self.nick = nick
+        self.special = special
+        self._refresh()
+
+    def __str__(self):
+        return self.nick
+
+    def addSpecial(self, special=""):
+        if special not in self.special:
+            self.special += special
+            self._refresh()
+
+    def _refresh(self):
+        special = "" if len(self.special) == 0 else " %s" % self.special
+        self.setHTML("<div class='occupant'>%s%s</div>" % (html_sanitize(self.nick), special))
+
+
+class OccupantsList(AbsolutePanel):
+    """Panel user to show occupants of a room"""
+
+    def __init__(self):
+        AbsolutePanel.__init__(self)
+        self.occupants_list = {}
+        self.setStyleName('occupantsList')
+
+    def addOccupant(self, nick):
+        _occupant = Occupant(nick)
+        self.occupants_list[nick] = _occupant
+        self.add(_occupant)
+
+    def removeOccupant(self, nick):
+        try:
+            self.remove(self.occupants_list[nick])
+        except KeyError:
+            print "ERROR: trying to remove an unexisting nick"
+
+    def clear(self):
+        self.occupants_list.clear()
+        AbsolutePanel.clear(self)
+
+    def addSpecials(self, occupants=[], html=""):
+        index = 0
+        special = html
+        for occupant in occupants:
+            if occupant in self.occupants_list.keys():
+                if isinstance(html, list):
+                    special = html[index]
+                    index = (index + 1) % len(html)
+                self.occupants_list[occupant].addSpecial(special)
+
+
+class PopupMenuPanel(PopupPanel):
+    """This implementation of a popup menu (context menu) allow you to assign
+    two special methods which are common to all the items, in order to hide
+    certain items and also easily define their callbacks. The menu can be
+    bound to any of the mouse button (left, middle, right).
+    """
+    def __init__(self, entries, hide=None, callback=None, vertical=True, style={}, **kwargs):
+        """
+        @param entries: a dict of dicts, where each sub-dict is representing
+        one menu item: the sub-dict key can be used as the item text and
+        description, but optional "title" and "desc" entries would be used
+        if they exists. The sub-dicts may be extended later to do
+        more complicated stuff or overwrite the common methods.
+        @param hide: function  with 2 args: widget, key as string and
+        returns True if that item should be hidden from the context menu.
+        @param callback: function with 2 args: sender, key as string
+        @param vertical: True or False, to set the direction
+        @param item_style: alternative CSS class for the menu items
+        @param menu_style: supplementary CSS class for the sender widget
+        """
+        PopupPanel.__init__(self, autoHide=True, **kwargs)
+        self._entries = entries
+        self._hide = hide
+        self._callback = callback
+        self.vertical = vertical
+        self.style = {"selected": None, "menu": "recipientTypeMenu", "item": "popupMenuItem"}
+        self.style.update(style)
+        self._senders = {}
+
+    def _show(self, sender):
+        """Popup the menu relative to this sender's position.
+        @param sender: the widget that has been clicked
+        """
+        menu = VerticalPanel() if self.vertical is True else HorizontalPanel()
+        menu.setStyleName(self.style["menu"])
+
+        def button_cb(item):
+            """You can not put that method in the loop and rely
+            on _key, because it is overwritten by each step.
+            You can rely on item.key instead, which is copied
+            from _key after the item creation.
+            @param item: the menu item that has been clicked
+            """
+            if self._callback is not None:
+                self._callback(sender=sender, key=item.key)
+            self.hide(autoClosed=True)
+
+        for _key in self._entries.keys():
+            entry = self._entries[_key]
+            if self._hide is not None and self._hide(sender=sender, key=_key) is True:
+                continue
+            title = entry["title"] if "title" in entry.keys() else _key
+            item = Button(title, button_cb)
+            item.key = _key
+            item.setStyleName(self.style["item"])
+            item.setTitle(entry["desc"] if "desc" in entry.keys() else title)
+            menu.add(item)
+        if len(menu.getChildren()) == 0:
+            return
+        self.add(menu)
+        if self.vertical is True:
+            x = sender.getAbsoluteLeft() + sender.getOffsetWidth()
+            y = sender.getAbsoluteTop()
+        else:
+            x = sender.getAbsoluteLeft()
+            y = sender.getAbsoluteTop() + sender.getOffsetHeight()
+        self.setPopupPosition(x, y)
+        self.show()
+        if self.style["selected"]:
+            sender.addStyleDependentName(self.style["selected"])
+
+        def _onHide(popup):
+            if self.style["selected"]:
+                sender.removeStyleDependentName(self.style["selected"])
+            return PopupPanel.onHideImpl(self, popup)
+
+        self.onHideImpl = _onHide
+
+    def registerClickSender(self, sender, button=BUTTON_LEFT):
+        """Bind the menu to the specified sender.
+        @param sender: the widget to which the menu should be bound
+        @param: BUTTON_LEFT, BUTTON_MIDDLE or BUTTON_RIGHT
+        """
+        self._senders.setdefault(sender, [])
+        self._senders[sender].append(button)
+
+        if button == BUTTON_RIGHT:
+            # WARNING: to disable the context menu is a bit tricky...
+            # The following seems to work on Firefox 24.0, but:
+            # TODO: find a cleaner way to disable the context menu
+            sender.getElement().setAttribute("oncontextmenu", "return false")
+
+        def _onBrowserEvent(event):
+            button = DOM.eventGetButton(event)
+            if DOM.eventGetType(event) == "mousedown" and button in self._senders[sender]:
+                self._show(sender)
+            return sender.__class__.onBrowserEvent(sender, event)
+
+        sender.onBrowserEvent = _onBrowserEvent
+
+    def registerMiddleClickSender(self, sender):
+        self.registerClickSender(sender, BUTTON_MIDDLE)
+
+    def registerRightClickSender(self, sender):
+        self.registerClickSender(sender, BUTTON_RIGHT)
+
+
+class ToggleStackPanel(StackPanel):
+    """This is a pyjamas.ui.StackPanel with modified behavior. All sub-panels ca be
+    visible at the same time, clicking a sub-panel header will not display it and hide
+    the others but only toggle its own visibility. The argument 'visibleStack' is ignored.
+    Note that the argument 'visible' has been added to listener's 'onStackChanged' method.
+    """
+
+    def __init__(self, **kwargs):
+        StackPanel.__init__(self, **kwargs)
+
+    def onBrowserEvent(self, event):
+        if DOM.eventGetType(event) == "click":
+            index = self.getDividerIndex(DOM.eventGetTarget(event))
+            if index != -1:
+                self.toggleStack(index)
+
+    def add(self, widget, stackText="", asHTML=False, visible=False):
+        StackPanel.add(self, widget, stackText, asHTML)
+        self.setStackVisible(self.getWidgetCount() - 1, visible)
+
+    def toggleStack(self, index):
+        if index >= self.getWidgetCount():
+            return
+        visible = not self.getWidget(index).getVisible()
+        self.setStackVisible(index, visible)
+        for listener in self.stackListeners:
+            listener.onStackChanged(self, index, visible)
--- a/browser_side/base_widget.py	Fri Jan 03 22:44:59 2014 +0100
+++ b/browser_side/base_widget.py	Sat Jan 04 00:17:46 2014 +0100
@@ -36,11 +36,12 @@
 from pyjamas.ui.ClickListener import ClickHandler
 from pyjamas.ui import HasAlignment
 from pyjamas import DOM
+from pyjamas import Window
+from __pyjamas__ import doc
+
 import dialog
 import logging
 from tools import LiberviaDragWidget
-from pyjamas import Window
-from __pyjamas__ import doc
 
 
 class DropCell(DropWidget):
--- a/browser_side/contact.py	Fri Jan 03 22:44:59 2014 +0100
+++ b/browser_side/contact.py	Sat Jan 04 00:17:46 2014 +0100
@@ -30,7 +30,8 @@
 from pyjamas import Window
 from pyjamas import DOM
 
-from browser_side.panels import ChatPanel, MicroblogPanel, PopupMenuPanel, WebPanel, UniBoxPanel
+from browser_side.base_panels import PopupMenuPanel
+from browser_side.panels import ChatPanel, MicroblogPanel, WebPanel, UniBoxPanel
 from browser_side.tools import DragLabel, html_sanitize, setPresenceStyle
 from __pyjamas__ import doc
 
--- a/browser_side/dialog.py	Fri Jan 03 22:44:59 2014 +0100
+++ b/browser_side/dialog.py	Sat Jan 04 00:17:46 2014 +0100
@@ -34,7 +34,9 @@
 from pyjamas.ui.KeyboardListener import KEY_ESCAPE, KEY_ENTER
 from pyjamas.ui.MouseListener import MouseWheelHandler
 from pyjamas import Window
-from browser_side import panels
+
+from base_panels import ToggleStackPanel
+
 from sat_frontends.tools.misc import DEFAULT_MUC
 
 # List here the patterns that are not allowed in contact group names
@@ -173,7 +175,7 @@
         self.room_panel = RoomChooser(host, "" if visible == (False, True) else DEFAULT_MUC)
         self.contact_panel = ContactsChooser(host, nb_contact, ok_button)
 
-        self.stack_panel = panels.ToggleStackPanel(Width="100%")
+        self.stack_panel = ToggleStackPanel(Width="100%")
         self.stack_panel.add(self.room_panel, title_room, visible=visible[0])
         self.stack_panel.add(self.contact_panel, title_invite, visible=visible[1])
         self.stack_panel.addStackChangeListener(self)
--- a/browser_side/list_manager.py	Fri Jan 03 22:44:59 2014 +0100
+++ b/browser_side/list_manager.py	Sat Jan 04 00:17:46 2014 +0100
@@ -35,7 +35,8 @@
 from pyjamas.ui.DragWidget import DragWidget
 from pyjamas.Timer import Timer
 from pyjamas import DOM
-import panels
+
+from base_panels import PopupMenuPanel
 
 
 # HTML content for the removal button (image or text)
@@ -236,7 +237,7 @@
 
     def registerPopupMenuPanel(self, entries, hide, callback):
         "Register a popup menu panel that will be bound to all contact keys elements."
-        self.popup_menu = panels.PopupMenuPanel(entries=entries, hide=hide, callback=callback, style={"item": self.style["popupMenuItem"]})
+        self.popup_menu = PopupMenuPanel(entries=entries, hide=hide, callback=callback, style={"item": self.style["popupMenuItem"]})
 
 
 class DragAutoCompleteTextBox(AutoCompleteTextBox, DragWidget, MouseHandler, FocusHandler):
--- a/browser_side/panels.py	Fri Jan 03 22:44:59 2014 +0100
+++ b/browser_side/panels.py	Sat Jan 04 00:17:46 2014 +0100
@@ -31,39 +31,36 @@
 from pyjamas.ui.Button import Button
 from pyjamas.ui.HTML import HTML
 from pyjamas.ui.Image import Image
-from pyjamas.ui.PopupPanel import PopupPanel
-from pyjamas.ui.StackPanel import StackPanel
 from pyjamas.ui.ClickListener import ClickHandler
 from pyjamas.ui.FlowPanel import FlowPanel
 from pyjamas.ui.KeyboardListener import KEY_ENTER, KEY_UP, KEY_DOWN, KeyboardHandler
-from pyjamas.ui.Event import BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT
 from pyjamas.ui.MouseListener import MouseHandler
+from pyjamas.ui.FocusListener import FocusHandler
 from pyjamas.Timer import Timer
 from pyjamas import DOM
+from pyjamas import Window
+from __pyjamas__ import doc
+
+from tools import html_sanitize, setPresenceStyle
+from base_panels import ChatText, OccupantsList, PopupMenuPanel
+from datetime import datetime
+from time import time
 from card_game import CardPanel
 from radiocol import RadioColPanel
 from menu import Menu
 from jid import JID
-from tools import html_sanitize, inlineRoot, setPresenceStyle
-from sat_frontends.tools.strings import addURLToText
-from datetime import datetime
-from time import time
 import dialog
 import base_widget
-from dialog import ConfirmDialog
 import richtext
+
+from constants import Const
 from plugin_xep_0085 import ChatStateMachine
-from pyjamas import Window
-from __pyjamas__ import doc
 from sat_frontends.tools.games import SYMBOLS
-from sat_frontends import constants
-from pyjamas.ui.FocusListener import FocusHandler
+from sat_frontends.tools.strings import addURLToText
+
 import logging
 
 
-const = constants.Const  # to directly import 'const' doesn't work
-
-
 class UniBoxPanel(HorizontalPanel):
     """Panel containing the UniBox"""
 
@@ -425,9 +422,9 @@
         self.bubble = self.editbox = self._current_comment = None
         self._setHeader()
         if self.empty:
-            self.editable_content = ['', const.SYNTAX_XHTML]
+            self.editable_content = ['', Const.SYNTAX_XHTML]
         else:
-            self.editable_content = [self.xhtml, const.SYNTAX_XHTML] if self.xhtml else [self.content, None]
+            self.editable_content = [self.xhtml, Const.SYNTAX_XHTML] if self.xhtml else [self.content, None]
             self.setEntryDialog()
         self._setIcons()
 
@@ -589,7 +586,7 @@
                 self._blog_panel.host.bridge.call('deleteMblog', None, self.pub_data, self.comments)
 
         target = 'message and all its comments' if self.comments else 'comment'
-        _dialog = ConfirmDialog(confirm_cb, text="Do you really want to delete this %s?" % target)
+        _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to delete this %s?" % target)
         _dialog.show()
 
     def _comment(self):
@@ -970,8 +967,8 @@
         self.status_panel = StatusPanel(host, status=status)
         self.setPresence(presence)
         entries = {}
-        for value in const.PRESENCE.keys():
-            entries.update({const.PRESENCE[value]: {"value": value}})
+        for value in Const.PRESENCE.keys():
+            entries.update({Const.PRESENCE[value]: {"value": value}})
 
         def callback(sender, key):
             self.setPresence(entries[key]["value"])  # order matters
@@ -996,8 +993,8 @@
 
     def setPresence(self, presence):
         status = self.status_panel.status
-        if not status.strip() or status == "&nbsp;" or (self.presence in const.PRESENCE and status == const.PRESENCE[self.presence]):
-            self.changeStatus(const.PRESENCE[presence])
+        if not status.strip() or status == "&nbsp;" or (self.presence in Const.PRESENCE and status == Const.PRESENCE[self.presence]):
+            self.changeStatus(Const.PRESENCE[presence])
         self.presence = presence
         setPresenceStyle(self.presence_button, self.presence)
 
@@ -1009,78 +1006,6 @@
         self.host.setSelected(None)
 
 
-class ChatText(HTMLPanel):
-
-    def __init__(self, timestamp, nick, mymess, msg, xhtml = None):
-        _date = datetime.fromtimestamp(float(timestamp or time()))
-        _msg_class = ["chat_text_msg"]
-        if mymess:
-            _msg_class.append("chat_text_mymess")
-        HTMLPanel.__init__(self, "<span class='chat_text_timestamp'>%(timestamp)s</span> <span class='chat_text_nick'>%(nick)s</span> <span class='%(msg_class)s'>%(msg)s</span>" %
-                           {"timestamp": _date.strftime("%H:%M"),
-                            "nick": "[%s]" % html_sanitize(nick),
-                            "msg_class": ' '.join(_msg_class),
-                            "msg": addURLToText(html_sanitize(msg)) if not xhtml else inlineRoot(xhtml)} #FIXME: images and external links must be removed according to preferences
-                           )
-        self.setStyleName('chatText')
-
-
-class Occupant(HTML):
-    """Occupant of a MUC room"""
-
-    def __init__(self, nick, special=""):
-        HTML.__init__(self)
-        self.nick = nick
-        self.special = special
-        self._refresh()
-
-    def __str__(self):
-        return self.nick
-
-    def addSpecial(self, special=""):
-        if special not in self.special:
-            self.special += special
-            self._refresh()
-
-    def _refresh(self):
-        special = "" if len(self.special) == 0 else " %s" % self.special
-        self.setHTML("<div class='occupant'>%s%s</div>" % (html_sanitize(self.nick), special))
-
-
-class OccupantsList(AbsolutePanel):
-    """Panel user to show occupants of a room"""
-
-    def __init__(self):
-        AbsolutePanel.__init__(self)
-        self.occupants_list = {}
-        self.setStyleName('occupantsList')
-
-    def addOccupant(self, nick):
-        _occupant = Occupant(nick)
-        self.occupants_list[nick] = _occupant
-        self.add(_occupant)
-
-    def removeOccupant(self, nick):
-        try:
-            self.remove(self.occupants_list[nick])
-        except KeyError:
-            print "ERROR: trying to remove an unexisting nick"
-
-    def clear(self):
-        self.occupants_list.clear()
-        AbsolutePanel.clear(self)
-
-    def addSpecials(self, occupants=[], html=""):
-        index = 0
-        special = html
-        for occupant in occupants:
-            if occupant in self.occupants_list.keys():
-                if isinstance(html, list):
-                    special = html[index]
-                    index = (index + 1) % len(html)
-                self.occupants_list[occupant].addSpecial(special)
-
-
 class ChatPanel(base_widget.LiberviaWidget):
 
     def __init__(self, host, target, type_='one2one'):
@@ -1390,139 +1315,3 @@
         """
         self.unibox_panel.setVisible(enable)
         return self.unibox_panel.setUniBox(enable)
-
-
-class PopupMenuPanel(PopupPanel):
-    """This implementation of a popup menu (context menu) allow you to assign
-    two special methods which are common to all the items, in order to hide
-    certain items and also easily define their callbacks. The menu can be
-    bound to any of the mouse button (left, middle, right).
-    """
-    def __init__(self, entries, hide=None, callback=None, vertical=True, style={}, **kwargs):
-        """
-        @param entries: a dict of dicts, where each sub-dict is representing
-        one menu item: the sub-dict key can be used as the item text and
-        description, but optional "title" and "desc" entries would be used
-        if they exists. The sub-dicts may be extended later to do
-        more complicated stuff or overwrite the common methods.
-        @param hide: function  with 2 args: widget, key as string and
-        returns True if that item should be hidden from the context menu.
-        @param callback: function with 2 args: sender, key as string
-        @param vertical: True or False, to set the direction
-        @param item_style: alternative CSS class for the menu items
-        @param menu_style: supplementary CSS class for the sender widget
-        """
-        PopupPanel.__init__(self, autoHide=True, **kwargs)
-        self._entries = entries
-        self._hide = hide
-        self._callback = callback
-        self.vertical = vertical
-        self.style = {"selected": None, "menu": "recipientTypeMenu", "item": "popupMenuItem"}
-        self.style.update(style)
-        self._senders = {}
-
-    def _show(self, sender):
-        """Popup the menu relative to this sender's position.
-        @param sender: the widget that has been clicked
-        """
-        menu = VerticalPanel() if self.vertical is True else HorizontalPanel()
-        menu.setStyleName(self.style["menu"])
-
-        def button_cb(item):
-            """You can not put that method in the loop and rely
-            on _key, because it is overwritten by each step.
-            You can rely on item.key instead, which is copied
-            from _key after the item creation.
-            @param item: the menu item that has been clicked
-            """
-            if self._callback is not None:
-                self._callback(sender=sender, key=item.key)
-            self.hide(autoClosed=True)
-
-        for _key in self._entries.keys():
-            entry = self._entries[_key]
-            if self._hide is not None and self._hide(sender=sender, key=_key) is True:
-                continue
-            title = entry["title"] if "title" in entry.keys() else _key
-            item = Button(title, button_cb)
-            item.key = _key
-            item.setStyleName(self.style["item"])
-            item.setTitle(entry["desc"] if "desc" in entry.keys() else title)
-            menu.add(item)
-        if len(menu.getChildren()) == 0:
-            return
-        self.add(menu)
-        if self.vertical is True:
-            x = sender.getAbsoluteLeft() + sender.getOffsetWidth()
-            y = sender.getAbsoluteTop()
-        else:
-            x = sender.getAbsoluteLeft()
-            y = sender.getAbsoluteTop() + sender.getOffsetHeight()
-        self.setPopupPosition(x, y)
-        self.show()
-        if self.style["selected"]:
-            sender.addStyleDependentName(self.style["selected"])
-
-        def _onHide(popup):
-            if self.style["selected"]:
-                sender.removeStyleDependentName(self.style["selected"])
-            return PopupPanel.onHideImpl(self, popup)
-
-        self.onHideImpl = _onHide
-
-    def registerClickSender(self, sender, button=BUTTON_LEFT):
-        """Bind the menu to the specified sender.
-        @param sender: the widget to which the menu should be bound
-        @param: BUTTON_LEFT, BUTTON_MIDDLE or BUTTON_RIGHT
-        """
-        self._senders.setdefault(sender, [])
-        self._senders[sender].append(button)
-
-        if button == BUTTON_RIGHT:
-            # WARNING: to disable the context menu is a bit tricky...
-            # The following seems to work on Firefox 24.0, but:
-            # TODO: find a cleaner way to disable the context menu
-            sender.getElement().setAttribute("oncontextmenu", "return false")
-
-        def _onBrowserEvent(event):
-            button = DOM.eventGetButton(event)
-            if DOM.eventGetType(event) == "mousedown" and button in self._senders[sender]:
-                self._show(sender)
-            return sender.__class__.onBrowserEvent(sender, event)
-
-        sender.onBrowserEvent = _onBrowserEvent
-
-    def registerMiddleClickSender(self, sender):
-        self.registerClickSender(sender, BUTTON_MIDDLE)
-
-    def registerRightClickSender(self, sender):
-        self.registerClickSender(sender, BUTTON_RIGHT)
-
-
-class ToggleStackPanel(StackPanel):
-    """This is a pyjamas.ui.StackPanel with modified behavior. All sub-panels ca be
-    visible at the same time, clicking a sub-panel header will not display it and hide
-    the others but only toggle its own visibility. The argument 'visibleStack' is ignored.
-    Note that the argument 'visible' has been added to listener's 'onStackChanged' method.
-    """
-
-    def __init__(self, **kwargs):
-        StackPanel.__init__(self, **kwargs)
-
-    def onBrowserEvent(self, event):
-        if DOM.eventGetType(event) == "click":
-            index = self.getDividerIndex(DOM.eventGetTarget(event))
-            if index != -1:
-                self.toggleStack(index)
-
-    def add(self, widget, stackText="", asHTML=False, visible=False):
-        StackPanel.add(self, widget, stackText, asHTML)
-        self.setStackVisible(self.getWidgetCount() - 1, visible)
-
-    def toggleStack(self, index):
-        if index >= self.getWidgetCount():
-            return
-        visible = not self.getWidget(index).getVisible()
-        self.setStackVisible(index, visible)
-        for listener in self.stackListeners:
-            listener.onStackChanged(self, index, visible)
--- a/browser_side/richtext.py	Fri Jan 03 22:44:59 2014 +0100
+++ b/browser_side/richtext.py	Sat Jan 04 00:17:46 2014 +0100
@@ -19,17 +19,17 @@
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 
-from dialog import ConfirmDialog
 from pyjamas.ui.TextArea import TextArea
 from pyjamas.ui.Button import Button
-from dialog import InfoDialog
 from pyjamas.ui.DialogBox import DialogBox
 from pyjamas.ui.Label import Label
 from pyjamas.ui.FlexTable import FlexTable
 from pyjamas.ui.HorizontalPanel import HorizontalPanel
+
+from dialog import ConfirmDialog, InfoDialog
 from list_manager import ListManager
+
 from sat_frontends.tools import composition
-import logging
 
 
 # used for onCloseCallback
--- a/libervia.py	Fri Jan 03 22:44:59 2014 +0100
+++ b/libervia.py	Sat Jan 04 00:17:46 2014 +0100
@@ -26,7 +26,7 @@
 from pyjamas.Timer import Timer
 from pyjamas import Window, DOM
 from pyjamas.JSONService import JSONProxy
-from pyjamas import Location
+
 from browser_side.register import RegisterBox
 from browser_side.contact import ContactPanel
 from browser_side.base_widget import WidgetsPanel
@@ -35,9 +35,11 @@
 from browser_side.jid import JID
 from browser_side.xmlui import XMLUI
 from browser_side.tools import html_sanitize
+
 from sat_frontends.tools.misc import InputHistory
 from sat_frontends.tools.strings import getURLParams
 from constants import Const
+from sat.core.i18n import _
 
 
 MAX_MBLOG_CACHE = 500  # Max microblog entries kept in memories
--- a/libervia.tac	Fri Jan 03 22:44:59 2014 +0100
+++ b/libervia.tac	Sat Jan 04 00:17:46 2014 +0100
@@ -33,15 +33,17 @@
 from twisted.words.protocols.jabber.jid import JID
 from txjsonrpc.web import jsonrpc
 from txjsonrpc import jsonrpclib
-from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService
+
 from logging import debug, info, warning, error
 import re, glob
 import os.path, sys
 import tempfile, shutil, uuid
-from server_side.blog import MicroBlog
 from zope.interface import Interface, Attribute, implements
 from xml.dom import minidom
+
 from constants import Const
+from server_side.blog import MicroBlog
+from sat_frontends.bridge.DBus import DBusBridgeFrontend, BridgeExceptionNoService
 from sat.core.i18n import _, D_