Mercurial > libervia-web
diff browser_side/richtext.py @ 254:28d3315a8003
browser_side: isolate the basic stuff of RecipientManager in a new class ListManager:
- renamed most occurences of "recipient" to "contact" and "recipient type" to "contact key" or "list"
- data to represent the lists and autocomplete values are parametrized
- UI elements styles are set by default but can be ovewritten by a sub-class
- popup menu for the list Button element has to be set with registerPopupMenuPanel
- richtext UI uses the definitions from sat.tool.frontends.composition
Know issues:
- drag and drop AutoCompleteTextBox corrupts the list of remaining autocomplete values
- selecting an autocomplete value with the mouse and not keybord is not working properly
author | souliane <souliane@mailoo.org> |
---|---|
date | Sat, 09 Nov 2013 09:38:17 +0100 |
parents | d4e73d9140af |
children | d3c734669577 |
line wrap: on
line diff
--- a/browser_side/richtext.py Sat Nov 09 08:53:03 2013 +0100 +++ b/browser_side/richtext.py Sat Nov 09 09:38:17 2013 +0100 @@ -27,73 +27,14 @@ from pyjamas.ui.Label import Label from pyjamas.ui.FlexTable import FlexTable from pyjamas.ui.HorizontalPanel import HorizontalPanel -from recipients import RECIPIENT_TYPES, RecipientManager - -BUTTONS = { - "bold": {"tip": "Bold", "icon": "media/icons/dokuwiki/toolbar/16/bold.png"}, - "italic": {"tip": "Italic", "icon": "media/icons/dokuwiki/toolbar/16/italic.png"}, - "underline": {"tip": "Underline", "icon": "media/icons/dokuwiki/toolbar/16/underline.png"}, - "code": {"tip": "Code", "icon": "media/icons/dokuwiki/toolbar/16/mono.png"}, - "strikethrough": {"tip": "Strikethrough", "icon": "media/icons/dokuwiki/toolbar/16/strike.png"}, - "heading": {"tip": "Heading", "icon": "media/icons/dokuwiki/toolbar/16/hequal.png"}, - "numberedlist": {"tip": "Numbered List", "icon": "media/icons/dokuwiki/toolbar/16/ol.png"}, - "list": {"tip": "List", "icon": "media/icons/dokuwiki/toolbar/16/ul.png"}, - "link": {"tip": "Link", "icon": "media/icons/dokuwiki/toolbar/16/linkextern.png"}, - "horizontalrule": {"tip": "Horizontal rule", "icon": "media/icons/dokuwiki/toolbar/16/hr.png"} - } - -# Define here your formats, the key must match the ones used in button. -# Tupples values must have 3 elements : prefix to the selection or cursor -# position, sample text to write if the marker is not applied on a selection, -# suffix to the selection or cursor position. -# FIXME: must be moved in backend and not harcoded like this -FORMATS = {"markdown": {"bold": ("**", "bold", "**"), - "italic": ("*", "italic", "*"), - "code": ("`", "code", "`"), - "heading": ("\n# ", "Heading 1", "\n## Heading 2\n"), - "list": ("\n* ", "item", "\n + subitem\n"), - "link": ("[desc](", "link", ")"), - "horizontalrule": ("\n***\n", "", "") - }, - "bbcode": {"bold": ("[b]", "bold", "[/b]"), - "italic": ("[i]", "italic", "[/i]"), - "underline": ("[u]", "underline", "[/u]"), - "strikethrough": ("[s]", "strikethrough", "[/s]"), - "code": ("[code]", "code", "[/code]"), - "link": ("[url=", "link", "]desc[/url]"), - "list": ("\n[list] [*]", "item 1", " [*]item 2 [/list]\n") - }, - "dokuwiki": {"bold": ("**", "bold", "**"), - "italic": ("//", "italic", "//"), - "underline": ("__", "underline", "__"), - "strikethrough": ("<del>", "strikethrough", "</del>"), - "code": ("<code>", "code", "</code>"), - "heading": ("\n==== ", "Heading 1", " ====\n=== Heading 2 ===\n"), - "link": ("[[", "link", "|desc]]"), - "list": ("\n * ", "item\n", "\n * subitem\n"), - "horizontalrule": ("\n----\n", "", "") - }, - "XHTML": {"bold": ("<b>", "bold", "</b>"), - "italic": ("<i>", "italic", "</i>"), - "underline": ("<u>", "underline", "</u>"), - "strikethrough": ("<s>", "strikethrough", "</s>"), - "code": ("<pre>", "code", "</pre>"), - "heading": ("\n<h3>", "Heading 1", "</h3>\n<h4>Heading 2</h4>\n"), - "link": ("<a href=\"", "link", "\">desc</a>"), - "list": ("\n<ul><li>", "item 1", "</li><li>item 2</li></ul>\n"), - "horizontalrule": ("\n<hr/>\n", "", "") - } - - } - -PARAM_KEY = "Composition" -PARAM_NAME = "Syntax" +from list_manager import ListManager +from sat.tools.frontends import composition class RichTextEditor(FlexTable): """Panel for the rich text editor.""" - def __init__(self, host, parent=None, onCloseCallback=None): + def __init__(self, host, parent, onCloseCallback=None): """Fill the editor with recipients panel, toolbar, text area...""" # TODO: don't forget to comment this before commit @@ -102,8 +43,8 @@ # This must be done before FlexTable.__init__ because it is used by setVisible self.host = host - offset1 = len(RECIPIENT_TYPES) - offset2 = len(FORMATS) if self._debug else 1 + offset1 = len(composition.RECIPIENT_TYPES) + offset2 = len(composition.RICH_FORMATS) if self._debug else 1 FlexTable.__init__(self, offset1 + offset2 + 2, 2) self.addStyleName('richTextEditor') @@ -112,7 +53,7 @@ # recipient types sub-panels are automatically added by the manager self.recipient = RecipientManager(self) - self.recipient.createWidgets() + self.recipient.createWidgets(title_format="%s: ") # Rich text tool bar is automatically added by setVisible @@ -138,9 +79,9 @@ to be also automatically removed from its parent, or the popup to be closed. @param host: the host - @popup parent: parent panel (in a popup if parent == None) . - @return: the RichTextEditor instance if popup is False, otherwise - a popup DialogBox containing the RichTextEditor. + @param parent: parent panel (or None to display in a popup). + @return: the RichTextEditor instance if parent is not None, + otherwise a popup DialogBox containing the RichTextEditor. """ if not hasattr(host, 'richtext'): host.richtext = RichTextEditor(host, parent, onCloseCallback) @@ -168,7 +109,7 @@ def setVisible(self, kwargs): """Called each time the widget is displayed, after creation or after having been hidden.""" - self.host.bridge.call('asyncGetParamA', self.setToolBar, PARAM_NAME, PARAM_KEY) or self.setToolBar(None) + self.host.bridge.call('asyncGetParamA', self.setToolBar, composition.PARAM_NAME_SYNTAX, composition.PARAM_KEY_COMPOSITION) or self.setToolBar(None) FlexTable.setVisible(self, kwargs) def __close(self): @@ -185,17 +126,17 @@ holding the rich text format is retrieved. It is called at each opening of the rich text editor because the user may have change his setting since the last time.""" - if _format is None or _format not in FORMATS.keys(): - _format = FORMATS.keys()[0] + if _format is None or _format not in composition.RICH_FORMATS.keys(): + _format = composition.RICH_FORMATS.keys()[0] if hasattr(self, "_format") and self._format == _format: return self._format = _format - offset1 = len(RECIPIENT_TYPES) + offset1 = len(composition.RECIPIENT_TYPES) count = 0 - for _format in FORMATS.keys() if self._debug else [self._format]: + for _format in composition.RICH_FORMATS.keys() if self._debug else [self._format]: toolbar = HorizontalPanel() toolbar.addStyleName('richTextToolbar') - for key in FORMATS[_format].keys(): + for key in composition.RICH_FORMATS[_format].keys(): self.addToolbarButton(toolbar, _format, key) label = Label("Format: %s" % _format) label.addStyleName("richTextFormatLabel") @@ -207,8 +148,8 @@ def addToolbarButton(self, toolbar, _format, key): """Add a button with the defined parameters.""" button = Button('<img src="%s" class="richTextIcon" />' % - BUTTONS[key]["icon"]) - button.setTitle(BUTTONS[key]["tip"]) + composition.RICH_BUTTONS[key]["icon"]) + button.setTitle(composition.RICH_BUTTONS[key]["tip"]) button.addStyleName('richTextToolButton') toolbar.add(button) @@ -217,7 +158,7 @@ text = self.textarea.getText() cursor_pos = self.textarea.getCursorPos() selection_length = self.textarea.getSelectionLength() - infos = FORMATS[_format][key] + infos = composition.RICH_FORMATS[_format][key] if selection_length == 0: middle_text = infos[1] else: @@ -235,7 +176,7 @@ def syncFromUniBox(self): """Synchronize from unibox.""" data, target = self.host.uni_box.getTargetAndData() - self.recipient.setRecipients({"To": [target]} if target else {}) + self.recipient.setContacts({"To": [target]} if target else {}) self.textarea.setText(data if data else "") def syncToUniBox(self, recipients=None): @@ -245,7 +186,7 @@ or if a recipient is set to an optional type (Cc, Bcc). @return True if the sync could be done, False otherwise""" if recipients is None: - recipients = self.recipient.getRecipients() + recipients = self.recipient.getContacts() target = "" # we could eventually allow more in the future allowed = 1 @@ -254,7 +195,7 @@ if count == 0: continue allowed -= count - if allowed < 0 or RECIPIENT_TYPES[key]["optional"]: + if allowed < 0 or composition.RECIPIENT_TYPES[key]["optional"]: return False # TODO: change this if later more then one recipients are allowed target = recipients[key][0] @@ -294,7 +235,7 @@ def sendMessage(self): """Send the message.""" - recipients = self.recipient.getRecipients() + recipients = self.recipient.getContacts() if self.syncToUniBox(recipients): # also check that we actually have a message target and data if len(recipients["To"]) > 0 and self.textarea.getText() != "": @@ -309,3 +250,19 @@ InfoDialog("Feature in development", "Sending a message to more the one recipient," + " to Cc or Bcc is not implemented yet!", Width="400px").center() + + +class RecipientManager(ListManager): + """A manager for sub-panels to set the recipients for each recipient type.""" + + def __init__(self, parent): + # TODO: be sure we also display empty groups and disconnected contacts + their groups + # store the full list of potential recipients (groups and contacts) + list_ = [] + list_.extend("@%s" % group for group in parent.host.contact_panel.getGroups()) + list_.extend(contact for contact in parent.host.contact_panel.getContacts()) + ListManager.__init__(self, parent, composition.RECIPIENT_TYPES, list_) + + self.registerPopupMenuPanel(entries=composition.RECIPIENT_TYPES, + hide=lambda sender, key: self.__children[key]["panel"].isVisible(), + callback=self.setContactPanelVisible)