Mercurial > libervia-web
view browser_side/menu.py @ 336:629c99bbd031
browser + server side: refactored menus:
- getMenus is added to Register class, so it can be used before being logged
- dynamic menus are added to main menu bar
- security limit is used
- menus use i18n
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 04 Feb 2014 16:49:20 +0100 |
parents | 4f221f34bdc7 |
children | 2067d6241927 |
line wrap: on
line source
#!/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.SimplePanel import SimplePanel from pyjamas.ui.VerticalPanel import VerticalPanel from pyjamas.ui.HorizontalPanel import HorizontalPanel from pyjamas.ui.DialogBox import DialogBox from pyjamas.ui.FormPanel import FormPanel from pyjamas.ui.FileUpload import FileUpload from pyjamas.ui.MenuBar import MenuBar from pyjamas.ui.MenuItem import MenuItem from pyjamas.ui.ListBox import ListBox from pyjamas.ui.Label import Label from pyjamas.ui.TextBox import TextBox from pyjamas.ui.Button import Button from pyjamas.ui.HTML import HTML from pyjamas.ui.Frame import Frame from pyjamas import Window from jid import JID from tools import html_sanitize from tools import FilterFileUpload from xmlui import XMLUI import panels import dialog from contact_group import ContactGroupEditor import re from sat.core.i18n import _ class MenuCmd: def __init__(self, object_, handler): self._object = object_ self._handler = handler def execute(self): handler = getattr(self._object, self._handler) handler() class PluginMenuCmd: def __init__(self, host, action_id): self.host = host self.action_id = action_id def execute(self): self.host.launchAction(self.action_id, None) class LiberviaMenuBar(MenuBar): def __init__(self): MenuBar.__init__(self, vertical=False) self.setStyleName('gwt-MenuBar-horizontal') # XXX: workaround for the Pyjamas' class name fix (it's now "gwt-MenuBar gwt-MenuBar-horizontal") # TODO: properly adapt CSS to the new class name def doItemAction(self, item, fireCommand): MenuBar.doItemAction(self, item, fireCommand) if item == self.items[-1] and self.popup: self.popup.setPopupPosition(Window.getClientWidth() - self.popup.getOffsetWidth() - 22, self.getAbsoluteTop() + self.getOffsetHeight() - 1) self.popup.addStyleName('menuLastPopup') class AvatarUpload(FormPanel): def __init__(self, close_cb=None): FormPanel.__init__(self) self.close_cb = close_cb self.setEncoding(FormPanel.ENCODING_MULTIPART) self.setMethod(FormPanel.METHOD_POST) self.setAction("upload_avatar") self.vPanel = VerticalPanel() self.message = HTML('Please select an image to show as your avatar...<br>Your picture must be a square and will be resized to 64x64 pixels if necessary') self.vPanel.add(self.message) hPanel = HorizontalPanel() hPanel.setSpacing(5) self.file_upload = FilterFileUpload("avatar_path", 2) self.vPanel.add(self.file_upload) hPanel.add(Button("Cancel", getattr(self, "onCloseBtnClick"))) self.upload_btn = Button("Upload avatar", getattr(self, "onSubmitBtnClick")) hPanel.add(self.upload_btn) self.status = Label() hPanel.add(self.status) self.vPanel.add(hPanel) self.add(self.vPanel) self.addFormHandler(self) def setCloseCb(self, close_cb): self.close_cb = close_cb def onCloseBtnClick(self): if self.close_cb: self.close_cb() else: print ("WARNING: no close method defined") def onSubmitBtnClick(self): if not self.file_upload.check(): return self.message.setHTML('<strong>Submitting, please wait...</strong>') self.upload_btn.setEnabled(False) self.submit() def onSubmit(self, event): pass def onSubmitComplete(self, event): result = event.getResults() if result != "OK": Window.alert("Can't open image... did you actually submit an image?") self.message.setHTML('Please select another image file') self.upload_btn.setEnabled(True) else: Window.alert("Your new profile picture has been set!") self.close_cb() class Menu(SimplePanel): def __init__(self, host): self.host = host SimplePanel.__init__(self) self.setStyleName('menuContainer') def createMenus(self, add_menus): _item_tpl = "<img src='media/icons/menu/%s_menu_red.png' />%s" menus_dict = {} menus_order = [] def addMenu(menu_name, menu_name_i18n, item_name_i18n, icon, menu_cmd): """ add a menu to menu_dict """ print "addMenu:",menu_name, menu_name_i18n, item_name_i18n, icon, menu_cmd try: menu_bar = menus_dict[menu_name] except KeyError: menu_bar = menus_dict[menu_name] = MenuBar(vertical=True) menus_order.append((menu_name, menu_name_i18n, icon)) menu_bar.addItem(item_name_i18n, menu_cmd) addMenu("General", _("General"), _("Web widget"), 'home', MenuCmd(self, "onWebWidget")) addMenu("General", _("General"), _("Disconnect"), 'home', MenuCmd(self, "onDisconnect")) addMenu("Contacts", _("Contacts"), _("Add contact"), 'social', MenuCmd(self, "onAddContact")) addMenu("Contacts", _("Contacts"), _("Update contact"), 'social', MenuCmd(self, "onUpdateContact")) addMenu("Contacts", _("Contacts"), _("Remove contact"), 'social', MenuCmd(self, "onRemoveContact")) addMenu("Contacts", _("Contacts"), _("Manage groups"), 'social', MenuCmd(self, "onManageContactGroups")) addMenu("Groups", _("Groups"), _("Discussion"), 'social', MenuCmd(self, "onJoinRoom")) addMenu("Groups", _("Groups"), _("Collective radio"), 'social', MenuCmd(self, "onCollectiveRadio")) addMenu("Games", _("Games"), _("Tarot"), 'games', MenuCmd(self, "onTarotGame")) addMenu("Games", _("Games"), _("Xiangqi"), 'games', MenuCmd(self, "onXiangqiGame")) # additional menus for action_id, type_, path, path_i18n in add_menus: if not path: print "WARNING: skipping menu without path" continue menu_name = path[0] menu_name_i18n = path_i18n[0] item_name_i18n = ' | '.join(path_i18n[1:]) if not item_name: print "WARNING: skipping menu with a path of lenght 1 [%s]" % path[0] continue addMenu(menu_name, menu_name_i18n, item_name_i18n, 'plugins', PluginMenuCmd(self.host, action_id)) menus_order.append(None) # we add separator addMenu("Help", _("Help"), _("Social contract"), 'help', MenuCmd(self, "onSocialContract")) addMenu("Help", _("Help"), _("About"), 'help', MenuCmd(self, "onAbout")) addMenu("Settings", _("Settings"), _("Parameters"), 'settings', MenuCmd(self, "onParameters")) # XXX: temporary, will change when a full profile will be managed in SàT addMenu("Settings", _("Settings"), _("Upload avatar"), 'settings', MenuCmd(self, "onAvatarUpload")) menubar = LiberviaMenuBar() for menu_data in menus_order: if menu_data is None: _separator = MenuItem('', None) _separator.setStyleName('menuSeparator') menubar.addItem(_separator, None) else: menu_name, menu_name_i18n, icon = menu_data menubar.addItem(MenuItem(_item_tpl % (icon, menu_name_i18n), True, menus_dict[menu_name])) self.add(menubar) #General menu def onWebWidget(self): web_panel = panels.WebPanel(self.host, "http://www.goffi.org") self.host.addWidget(web_panel) self.host.setSelected(web_panel) def onDisconnect(self): def confirm_cb(answer): if answer: print "disconnection" self.host.bridge.call('disconnect', None) _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to disconnect ?") _dialog.show() def onSocialContract(self): _frame = Frame('contrat_social.html') _frame.setStyleName('infoFrame') _dialog = dialog.GenericDialog("Contrat Social", _frame) _dialog.setSize('80%', '80%') _dialog.show() def onAbout(self): _about = HTML("""<b>Libervia</b>, a Salut à Toi project<br /> <br /> You can contact the author at <a href="mailto:goffi@goffi.org">goffi@goffi.org</a><br /> Blog available (mainly in french) at <a href="http://www.goffi.org" target="_blank">http://www.goffi.org</a><br /> Project page: <a href="http://sat.goffi.org"target="_blank">http://sat.goffi.org</a><br /> <br /> Any help welcome :) <p style='font-size:small;text-align:center'>This project is dedicated to Roger Poisson</p> """) _dialog = dialog.GenericDialog("About", _about) _dialog.show() #Contact menu def onAddContact(self): """Q&D contact addition""" _dialog = None edit = TextBox() def addContactCb(sender): if not re.match(r'^.+@.+\..+', edit.getText(), re.IGNORECASE): Window.alert('You must enter a valid contact JID (like "contact@%s")' % self.host._defaultDomain) _dialog.show() else: self.host.bridge.call('addContact', None, edit.getText(), '', _dialog.getSelectedGroups() ) label = Label("New contact identifier (JID):") edit.setText('@%s' % self.host._defaultDomain) edit.setWidth('100%') _dialog = dialog.GroupSelector([label, edit], self.host.contact_panel.getGroups(), [], "Add", addContactCb) _dialog.setHTML('Adding contact') _dialog.show() def onUpdateContact(self): _dialog = None _contacts_list = ListBox() def updateContactCb(sender): _jid = _contacts_list.getValue(_contacts_list.getSelectedIndex()) self.host.bridge.call('updateContact', None, _jid, '', _dialog.getSelectedGroups()) def onContactChange(_list): _jid = _contacts_list.getValue(_contacts_list.getSelectedIndex()) groups = self.host.contact_panel.getContactGroups(_jid) _dialog.setGroupsSelected(groups) for contact in self.host.contact_panel.getContacts(): _contacts_list.addItem(contact) _contacts_list.addChangeListener(onContactChange) _jid = _contacts_list.getValue(_contacts_list.getSelectedIndex()) _selected_groups = self.host.contact_panel.getContactGroups(_jid) _dialog = dialog.GroupSelector([Label('Which contact do you want to update ?'), _contacts_list], self.host.contact_panel.getGroups(), _selected_groups, "Update", updateContactCb) _dialog.setHTML('Updating contact') _dialog.show() def onRemoveContact(self): _dialog = None _contacts_list = ListBox() def secondConfirmCb(confirm): if confirm: for contact in _contacts_list.getSelectedValues(): self.host.bridge.call('delContact', None, contact) else: _dialog.show() def dialogCb(confirm): if confirm: html_list = ''.join(['<li>%s</li>' % html_sanitize(contact) for contact in _contacts_list.getSelectedValues()]) html_body = "Are you sure to remove the following contacts from your contact list ?<ul>%s</ul>" % html_list dialog.ConfirmDialog(secondConfirmCb, html_body).show() for contact in self.host.contact_panel.getContacts(): _contacts_list.addItem(contact) _dialog = dialog.GenericConfirmDialog([_contacts_list], dialogCb, "Who do you want to remove from your contacts ?") _dialog.show() def onManageContactGroups(self): """Open the contact groups manager.""" def onCloseCallback(): pass ContactGroupEditor(self.host, None, onCloseCallback) #Group menu def onJoinRoom(self): def invite(room_jid, contacts): for contact in contacts: self.host.bridge.call('inviteMUC', None, contact, room_jid) def join(room_jid, contacts): if self.host.whoami: nick = self.host.whoami.node if room_jid not in [room.bare for room in self.host.room_list]: self.host.bridge.call('joinMUC', lambda room_jid: invite(room_jid, contacts), room_jid, nick) else: self.host.getOrCreateLiberviaWidget(panels.ChatPanel, (room_jid, "group"), True, JID(room_jid).bare) invite(room_jid, contacts) dialog.RoomAndContactsChooser(self.host, join, ok_button="Join", visible=(True, False)) def onCollectiveRadio(self): def callback(room_jid, contacts): self.host.bridge.call('launchRadioCollective', None, contacts, room_jid) dialog.RoomAndContactsChooser(self.host, callback, ok_button="Choose", title="Collective Radio", visible=(False, True)) #Game menu def onTarotGame(self): def onPlayersSelected(room_jid, other_players): self.host.bridge.call('launchTarotGame', None, other_players, room_jid) dialog.RoomAndContactsChooser(self.host, onPlayersSelected, 3, title="Tarot", title_invite="Please select 3 other players", visible=(False, True)) def onXiangqiGame(self): Window.alert("A Xiangqi game is planed, but not available yet") #Settings menu def onParameters(self): def gotParams(xmlui): if not xmlui: return body = XMLUI(self.host, xmlui) _dialog = dialog.GenericDialog("Parameters", body, options=['NO_CLOSE']) body.setCloseCb(_dialog.close) _dialog.setSize('80%', '80%') _dialog.show() self.host.bridge.call('getParamsUI', gotParams) def removeItemParams(self): """Remove the Parameters item from the Settings menu bar.""" self.menu_settings.removeItem(self.item_params) def onAvatarUpload(self): body = AvatarUpload() _dialog = dialog.GenericDialog("Avatar upload", body, options=['NO_CLOSE']) body.setCloseCb(_dialog.close) _dialog.setSize('40%', '40%') _dialog.show()