# HG changeset patch # User souliane # Date 1386599643 -3600 # Node ID 36ce989c73a5df0d98729e839118ff63a515d7ab # Parent 1ccdc34cfb60dd0ae71f8e3d46137381ae897070 browser_side: more customizable rich text editor diff -r 1ccdc34cfb60 -r 36ce989c73a5 browser_side/richtext.py --- a/browser_side/richtext.py Wed Dec 04 21:52:30 2013 +0100 +++ b/browser_side/richtext.py Mon Dec 09 15:34:03 2013 +0100 @@ -29,13 +29,23 @@ from pyjamas.ui.HorizontalPanel import HorizontalPanel from list_manager import ListManager from sat_frontends.tools import composition +import logging + + +# used for onCloseCallback +CANCEL, SYNC_NOT_SAVE, SAVE = xrange(0, 3) class RichTextEditor(FlexTable): """Panel for the rich text editor.""" - def __init__(self, host, parent, onCloseCallback=None): - """Fill the editor with recipients panel, toolbar, text area...""" + def __init__(self, host, parent, onCloseCallback=None, options=()): + """Fill the editor with recipients panel, toolbar, text area... + @param host: the SatWebFrontend instance + @param parent: the parent panel + @param onCloseCallback: method to call when the dialog is closed + @param options: list of options: 'no_recipient', 'no_command', 'no_style'... + """ # TODO: don't forget to comment this before commit self._debug = False @@ -43,33 +53,49 @@ # This must be done before FlexTable.__init__ because it is used by setVisible self.host = host - offset1 = len(composition.RECIPIENT_TYPES) + self.no_close = 'no_close' in options + self.update_msg = 'update_msg' in options + self.no_recipient = 'no_recipient' in options + self.no_command = 'no_command' in options + self.no_sync_unibox = self.no_command or 'no_sync_unibox' in options + self.no_main_style = 'no_style' in options or 'no_main_style' in options + self.no_toolbar_style = 'no_style' in options or 'no_toolbar_style' in options + self.no_textarea_style = 'no_style' in options or 'no_textarea_style' in options + + offset1 = 0 if self.no_recipient else len(composition.RECIPIENT_TYPES) offset2 = len(composition.RICH_FORMATS) if self._debug else 1 - FlexTable.__init__(self, offset1 + offset2 + 2, 2) - self.addStyleName('richTextEditor') + offset3 = 0 if self.no_command else 1 + FlexTable.__init__(self, offset1 + offset2 + 1 + offset3, 2) + if not self.no_main_style: + self.addStyleName('richTextEditor') self._parent = parent self._on_close_callback = onCloseCallback - # recipient types sub-panels are automatically added by the manager - self.recipient = RecipientManager(self) - self.recipient.createWidgets(title_format="%s: ") + if not self.no_recipient: + # recipient types sub-panels are automatically added by the manager + self.recipient = RecipientManager(self) + self.recipient.createWidgets(title_format="%s: ") # Rich text tool bar is automatically added by setVisible self.textarea = TextArea() - self.textarea.addStyleName('richTextArea') - - self.command = HorizontalPanel() - self.command.addStyleName("marginAuto") - self.command.add(Button("Cancel", listener=self.cancelWithoutSaving)) - self.command.add(Button("Back to quick box", listener=self.closeAndSave)) - self.command.add(Button("Send message", listener=self.sendMessage)) + if not self.no_textarea_style: + self.textarea.addStyleName('richTextArea') self.getFlexCellFormatter().setColSpan(offset1 + offset2, 0, 2) - self.getFlexCellFormatter().setColSpan(offset1 + offset2 + 1, 0, 2) self.setWidget(offset1 + offset2, 0, self.textarea) - self.setWidget(offset1 + offset2 + 1, 0, self.command) + + if not self.no_command: + self.command = HorizontalPanel() + self.command.addStyleName("marginAuto") + self.command.add(Button("Cancel", listener=self.cancelWithoutSaving)) + if not self.no_sync_unibox: + self.command.add(Button("Back to quick box", listener=self.closeAndSave)) + self.command.add(Button("Update" if self.update_msg else "Send message", + listener=self.__close if self.update_msg else self.sendMessage)) + self.getFlexCellFormatter().setColSpan(offset1 + offset2 + 1, 0, 2) + self.setWidget(offset1 + offset2 + 1, 0, self.command) @classmethod def getOrCreate(cls, host, parent=None, onCloseCallback=None): @@ -113,14 +139,15 @@ if visible: self.host.bridge.call('asyncGetParamA', self.setToolBar, composition.PARAM_NAME_SYNTAX, composition.PARAM_KEY_COMPOSITION) or self.setToolBar(None) - def __close(self): + def __close(self, result=SAVE): """Remove the widget from parent or close the popup.""" - if self._parent is None: - self.popup.hide() - else: - self.setVisible(False) + if not self.no_close: + if self._parent is None: + self.popup.hide() + else: + self.setVisible(False) if self._on_close_callback is not None: - self._on_close_callback() + self._on_close_callback(result) def setToolBar(self, _format): """This method is called asynchronously after the parameter @@ -132,11 +159,12 @@ if hasattr(self, "_format") and self._format == _format: return self._format = _format - offset1 = len(composition.RECIPIENT_TYPES) + offset1 = 0 if self.no_recipient else len(composition.RECIPIENT_TYPES) count = 0 for _format in composition.RICH_FORMATS.keys() if self._debug else [self._format]: toolbar = HorizontalPanel() - toolbar.addStyleName('richTextToolbar') + if not self.no_toolbar_style: + toolbar.addStyleName('richTextToolbar') for key in composition.RICH_FORMATS[_format].keys(): self.addToolbarButton(toolbar, _format, key) label = Label("Format: %s" % _format) @@ -177,12 +205,19 @@ def syncFromUniBox(self): """Synchronize from unibox.""" data, target = self.host.uni_box.getTargetAndData() - self.recipient.setContacts({"To": [target]} if target else {}) + if hasattr(self, 'recipient'): + self.recipient.setContacts({"To": [target]} if target else {}) self.textarea.setText(data if data else "") def syncToUniBox(self, recipients=None, emptyText=False): """Synchronize to unibox if a maximum of one recipient is set. @return True if the sync could be done, False otherwise""" + def setText(): + self.host.uni_box.setText("" if emptyText else self.textarea.getText()) + + if not hasattr(self, 'recipient'): + setText() + return True if recipients is None: recipients = self.recipient.getContacts() target = "" @@ -197,7 +232,7 @@ return False # TODO: change this if later more then one recipients are allowed target = recipients[key][0] - self.host.uni_box.setText("" if emptyText else self.textarea.getText()) + setText() from panels import ChatPanel, MicroblogPanel if target == "": return True @@ -211,18 +246,22 @@ def cancelWithoutSaving(self): """Ask for confirmation before closing the dialog.""" + if self.update_msg and self.original_text and self.textarea.getText() == self.original_text: + self.__close(CANCEL) + return + def confirm_cb(answer): if answer: - self.__close() + self.__close(CANCEL) - _dialog = ConfirmDialog(confirm_cb, text="Do you really want to cancel this message?") + _dialog = ConfirmDialog(confirm_cb, text="Do you really want to %s?" % ("cancel your changes" if self.update_msg else "cancel this message")) _dialog.show() def closeAndSave(self): """Synchronize to unibox and close the dialog afterward. Display a message and leave the dialog open if the sync was not possible.""" if self.syncToUniBox(): - self.__close() + self.__close(SYNC_NOT_SAVE) return InfoDialog("Too many recipients", "A message with more than one direct recipient (To)," + @@ -249,7 +288,7 @@ return self.syncToUniBox(recipients, emptyText=True) self.host.send(targets, text, extra={'rich': text}) - self.__close() + self.__close(SAVE) class RecipientManager(ListManager):