Mercurial > libervia-web
diff browser_side/panels.py @ 282:ae3ec654836d
browser_side: added blog item modification/deletion
author | souliane <souliane@mailoo.org> |
---|---|
date | Tue, 10 Dec 2013 09:07:03 +0100 |
parents | 2d6bd975a72d |
children | 4f0c2fea358a |
line wrap: on
line diff
--- a/browser_side/panels.py Mon Dec 09 15:34:03 2013 +0100 +++ b/browser_side/panels.py Tue Dec 10 09:07:03 2013 +0100 @@ -34,10 +34,9 @@ from pyjamas.ui.PopupPanel import PopupPanel from pyjamas.ui.StackPanel import StackPanel from pyjamas.ui.ClickListener import ClickHandler -from pyjamas.ui.KeyboardListener import KEY_ENTER, KEY_UP, KEY_DOWN +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.ListBox import ListBox from pyjamas.Timer import Timer from pyjamas import DOM from card_game import CardPanel @@ -49,13 +48,15 @@ from time import time import dialog import base_widget -from richtext import RichTextEditor +from dialog import ConfirmDialog +import richtext 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.ContextMenuPopupPanel import ContextMenuPopupPanel +from pyjamas.ui.FocusListener import FocusHandler +import logging const = constants.Const # to directly import 'const' doesn't work @@ -95,7 +96,7 @@ self.unibox.setVisible(True) self.host.resize() - RichTextEditor.getOrCreate(self.host, self, onCloseCallback) + richtext.RichTextEditor.getOrCreate(self.host, self, onCloseCallback) self.host.resize() @@ -318,35 +319,64 @@ print "Warning: can't manage comment [%s], some keys are missing in microblog data (%s)" % (data["comments"], data.keys()) self.comments = False if set(("service", "node")).issubset(data.keys()): + # comment item self.service = data["service"] self.node = data["node"] - self.hash = (self.service, self.node) + else: + # main item + try: + self.service = data['comments_service'] + self.node = data['comments_node'] + except KeyError: + logging.error("Main item %s is missing its comments information!" % self.id) + self.hash = (self.service, self.node) -class MicroblogEntry(SimplePanel, ClickHandler): +class MicroblogEntry(SimplePanel, ClickHandler, FocusHandler, KeyboardHandler): def __init__(self, blog_panel, mblog_entry): SimplePanel.__init__(self) self._blog_panel = blog_panel + self.entry = mblog_entry self.author = mblog_entry.author self.timestamp = mblog_entry.timestamp _datetime = datetime.fromtimestamp(mblog_entry.timestamp) self.comments = mblog_entry.comments + self.pub_data = (mblog_entry.hash[0], mblog_entry.hash[1], mblog_entry.id) + self.editable_content = (mblog_entry.xhtml, const._SYNTAX_XHTML) if mblog_entry.xhtml else (mblog_entry.content, None) self.panel = HTMLPanel(""" <div class='mb_entry_header'><span class='mb_entry_author'>%(author)s</span> on <span class='mb_entry_timestamp'>%(timestamp)s</span></div> + <div class='mb_entry_delete_update'> + <div id="id_delete"></div> + <div id="id_update"></div> + </div> <div class="mb_entry_avatar" id='id_avatar'></div> - <div class="mb_entry_dialog"> - <div class="bubble">%(body)s</div> + <div class="mb_entry_dialog" id='id_entry_dialog'></div> </div> """ % {"author": html_sanitize(self.author), - "timestamp": _datetime, - "body": addURLToText(html_sanitize(mblog_entry.content)) if not mblog_entry.xhtml else mblog_entry.xhtml + "timestamp": _datetime }) self.avatar = Image(blog_panel.host.getAvatar(self.author)) self.panel.add(self.avatar, "id_avatar") + body = addURLToText(html_sanitize(mblog_entry.content)) if not mblog_entry.xhtml else mblog_entry.xhtml + self.bubble = HTML(body) + self.bubble.setStyleName("bubble") + self.panel.add(self.bubble, "id_entry_dialog") self.panel.setStyleName('mb_entry') + if self.author == blog_panel.host.whoami.bare: + self.delete_label = Label(u"✗") + self.delete_label.setTitle("Delete this message") + self.panel.add(self.delete_label, "id_delete") + self.update_label = Label(u"✍") + self.update_label.setTitle("Edit this message") + self.panel.add(self.update_label, "id_update") + self.delete_label.addClickListener(self) + self.update_label.addClickListener(self) + else: + self.modify_label = self.delete_label = None + self.editbox = None self.add(self.panel) ClickHandler.__init__(self) self.addClickListener(self) @@ -357,8 +387,87 @@ self.avatar.setUrl(new_avatar) def onClick(self, sender): - print "microblog entry selected (author=%s)" % self.author - self._blog_panel.setSelectedEntry(self if self.comments else None) + if sender == self: + self._blog_panel.setSelectedEntry(self if self.comments else None) + elif sender == self.update_label: + self._update() + elif sender == self.delete_label: + self._delete() + + def onKeyUp(self, sender, keycode, modifiers): + """Update is done when ENTER key is pressed within the raw editbox""" + if sender != self.editbox or not self.editbox.getVisible(): + return + if keycode == KEY_ENTER: + self.updateContent() + + def onLostFocus(self, sender): + """Update is done when the focus leaves the raw editbox""" + if sender != self.editbox or not self.editbox.getVisible(): + return + self.updateContent() + + def updateContent(self, cancel=False): + """Send the new content to the backend""" + if not self.editbox or not self.editbox.getVisible(): + return + self.panel.remove(self.edit_panel) + self.panel.add(self.bubble, "id_entry_dialog") + new_text = self.editbox.getText().strip() + self.edit_panel = self.editbox = None + if cancel or new_text == self.editable_content[0] or new_text == "": + return + self.editable_content[0] = new_text + self._blog_panel.host.bridge.call('updateMblog', None, self.pub_data, self.comments, new_text, + {'rich': new_text} if self.entry.xhtml else {}) + + def _update(self): + """Change the bubble to an editbox""" + if self.editbox and self.editbox.getVisible(): + return + + def setOriginalText(text, container): + text = text.strip() + container.original_text = text + self.editbox.setWidth('100%') + self.editbox.setText(text) + panel = SimplePanel() + panel.add(container) + panel.setStyleName("bubble") + panel.addStyleName('bubble-editbox') + self.bubble.removeFromParent() + self.panel.add(panel, "id_entry_dialog") + self.editbox.setFocus(True) + self.editbox.setSelectionRange(len(text), 0) + self.edit_panel = panel + self.editable_content = (text, container.format if isinstance(container, richtext.RichTextEditor) else None) + + if self.entry.xhtml: + options = ('no_recipient', 'no_sync_unibox', 'no_style', 'update_msg', 'no_close') + + def cb(result): + self.updateContent(result == richtext.CANCEL) + + editor = richtext.RichTextEditor(self._blog_panel.host, self.panel, cb, options=options) + editor.setVisible(True) # needed to build the toolbar + self.editbox = editor.textarea + self._blog_panel.host.bridge.call('syntaxConvert', lambda d: setOriginalText(d, editor), + self.editable_content[0], self.editable_content[1]) + else: + self.editbox = TextArea() + self.editbox.addFocusListener(self) + self.editbox.addKeyboardListener(self) + setOriginalText(self.editable_content[0], self.editbox) + + def _delete(self): + """Ask confirmation for deletion""" + def confirm_cb(answer): + if answer: + 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.show() class MicroblogPanel(base_widget.LiberviaWidget): @@ -527,30 +636,65 @@ sub_panel.setStyleName('microblogPanel') sub_panel.addStyleName('subPanel') self.vpanel.insert(sub_panel, parent_idx + 1) - + for idx in xrange(0, len(sub_panel.getChildren())): + comment = sub_panel.getIndexedChild(idx) + if comment.pub_data[2] == mblog_item.id: + # update an existing comment + sub_panel.remove(comment) + sub_panel.insert(_entry, idx) + return # we want comments to be inserted in chronological order self._chronoInsert(sub_panel, _entry, reverse=False) return - if mblog_item.id in self.entries: - return + update = mblog_item.id in self.entries _entry = MicroblogEntry(self, mblog_item) - + if update: + idx = self.vpanel.getWidgetIndex(self.entries[mblog_item.id]) + self.vpanel.remove(self.entries[mblog_item.id]) + self.vpanel.insert(_entry, idx) + else: + self._chronoInsert(self.vpanel, _entry) self.entries[mblog_item.id] = _entry - self._chronoInsert(self.vpanel, _entry) - if mblog_item.comments: # entry has comments, we keep the comment node as a reference self.comments[mblog_item.comments_hash] = _entry self.host.bridge.call('getMblogComments', self.mblogsInsert, mblog_item.comments_service, mblog_item.comments_node) + def removeEntry(self, type_, id_): + """Remove an entry from the panel + @param type_: entry type ('main_item' or 'comment') + @param id_: entry id + """ + for child in self.vpanel.getChildren(): + if isinstance(child, MicroblogEntry) and type_ == 'main_item': + print child.pub_data + if child.pub_data[2] == id_: + main_idx = self.vpanel.getWidgetIndex(child) + try: + sub_panel = self.vpanel.getWidget(main_idx + 1) + if isinstance(sub_panel, VerticalPanel): + sub_panel.removeFromParent() + except IndexError: + pass + child.removeFromParent() + self.selected_entry = None + break + elif isinstance(child, VerticalPanel) and type_ == 'comment': + for comment in child.getChildren(): + if comment.pub_data[2] == id_: + comment.removeFromParent() + self.selected_entry = None + break + def setSelectedEntry(self, entry): if self.selected_entry == entry: entry = None if self.selected_entry: self.selected_entry.removeStyleName('selected_entry') if entry: + print "microblog entry selected (author=%s)" % entry.author entry.addStyleName('selected_entry') self.selected_entry = entry