# HG changeset patch # User souliane # Date 1391800451 -3600 # Node ID f1ba38043d788774aa1e0e556e4aa6d1f62cfff6 # Parent 82f9e92379b062c1e1641710a9d7fcf404c0deab browser_side: status panel is based on a new class LightTextEditor which uses HTML5 "editablecontent" property diff -r 82f9e92379b0 -r f1ba38043d78 browser_side/base_panels.py --- a/browser_side/base_panels.py Fri Feb 07 20:08:28 2014 +0100 +++ b/browser_side/base_panels.py Fri Feb 07 20:14:11 2014 +0100 @@ -28,12 +28,14 @@ from pyjamas.ui.StackPanel import StackPanel from pyjamas.ui.TextArea import TextArea from pyjamas.ui.Event import BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT +from pyjamas.ui.KeyboardListener import KEY_ENTER, KeyboardHandler +from pyjamas.ui.FocusListener import FocusHandler from pyjamas import DOM from datetime import datetime from time import time -from tools import html_sanitize, inlineRoot +from tools import html_sanitize, html_clean, inlineRoot from sat_frontends.tools.strings import addURLToText from sat.core.i18n import _ @@ -285,3 +287,56 @@ def setText(self, text): self.text_area.setText(text) + + +class LightTextEditor(HTML, FocusHandler, KeyboardHandler): + + def __init__(self, content='', single_line=False, callback=None): + HTML.__init__(self) + if single_line: + FocusHandler.__init__(self) + KeyboardHandler.__init__(self) + self.__single_line = single_line + self.__callback = callback + self.setContent(content) + + def setContent(self, content=''): + self.__original_content = html_clean(content) if self.__single_line else content.strip() + self.setHTML('
%s
' % self.__original_content) + + def getContent(self): + content = DOM.getInnerHTML(self.getElement().firstChild) + return html_clean(content) if self.__single_line else content.strip() + + def modified(self, content=None): + if content is None: + content = self.getContent() + return content != self.__original_content + + def edit(self, edit): + self.getElement().setAttribute('contenteditable', 'true' if edit else 'false') + if edit: + self.setFocus(True) + if self.__single_line: + self.addFocusListener(self) + self.addKeyboardListener(self) + else: + if self.__single_line: + self.removeFocusListener(self) + self.removeKeyboardListener(self) + content = self.getContent() + if self.modified(content) and self.__callback: + self.__callback(content) + + def setFocus(self, focus): + if focus: + self.getElement().focus() + else: + self.getElement().blur() + + def onKeyDown(self, sender, keycode, modifiers): + if keycode == KEY_ENTER: + self.setFocus(False) + + def onLostFocus(self, sender): + self.edit(False) diff -r 82f9e92379b0 -r f1ba38043d78 browser_side/panels.py --- a/browser_side/panels.py Fri Feb 07 20:08:28 2014 +0100 +++ b/browser_side/panels.py Fri Feb 07 20:14:11 2014 +0100 @@ -40,7 +40,7 @@ from __pyjamas__ import doc from tools import html_sanitize, setPresenceStyle -from base_panels import ChatText, OccupantsList, PopupMenuPanel +from base_panels import ChatText, OccupantsList, PopupMenuPanel, LightTextEditor from datetime import datetime from time import time from card_game import CardPanel @@ -897,52 +897,27 @@ return False -class StatusPanel(HTMLPanel, ClickHandler, FocusHandler, KeyboardHandler): +class StatusPanel(LightTextEditor, ClickHandler): EMPTY_STATUS = '' def __init__(self, host, status=''): self.host = host self.status = status - HTMLPanel.__init__(self, self.__getContent()) + LightTextEditor.__init__(self, self.__getStatus(), True, lambda status: self.host.bridge.call('setStatus', None, self.host.status_panel.presence, status)) self.setStyleName('statusPanel') ClickHandler.__init__(self) - FocusHandler.__init__(self) - KeyboardHandler.__init__(self) self.addClickListener(self) - def __getContent(self): - return "%(status)s" % {'status': html_sanitize(self.status or self.EMPTY_STATUS)} + def __getStatus(self): + return html_sanitize(self.status or self.EMPTY_STATUS) def changeStatus(self, new_status): self.status = new_status - self.setHTML(self.__getContent()) + self.setContent(self.__getStatus()) def onClick(self, sender): - self.textarea = TextArea() - self.textarea.setStyleName('status-edit') - self.textarea.setText(self.status) - self.textarea.addKeyboardListener(self) - self.setVisible(False) - self.parent.insert(self.textarea, self.parent.getWidgetIndex(self)) - self.textarea.setFocus(True) - self.textarea.setSelectionRange(0, len(self.status)) - self.textarea.addFocusListener(self) - self.textarea.addKeyboardListener(self) - - def onKeyPress(self, sender, keycode, modifiers): - text = self.textarea.getText() - - if keycode == KEY_ENTER: - if text != self.status: - self.host.bridge.call('setStatus', None, self.host.status_panel.presence, text) - self.parent.remove(self.textarea) - self.setVisible(True) - - def onLostFocus(self, sender): - FocusHandler.onLostFocus(self, sender) - if sender == self.textarea: - self.onKeyPress(self, KEY_ENTER, None) + self.edit(True) class PresenceStatusPanel(HorizontalPanel, ClickHandler): diff -r 82f9e92379b0 -r f1ba38043d78 browser_side/tools.py --- a/browser_side/tools.py Fri Feb 07 20:08:28 2014 +0100 +++ b/browser_side/tools.py Fri Feb 07 20:14:11 2014 +0100 @@ -22,6 +22,7 @@ from pyjamas import Window from nativedom import NativeDOM from sat_frontends.tools import xmltools +import re dom = NativeDOM() @@ -31,6 +32,30 @@ return html.replace('<', '<').replace('>', '>') +def html_clean(html): + """ + Remove HTML markup from the given string. + Copied from nltk.clean_html (http://www.nltk.org/) + + @param html: the HTML string to be cleaned + @type html: C{string} + @rtype: C{string} + """ + + # First we remove inline JavaScript/CSS: + cleaned = re.sub(r"(?is)<(script|style).*?>.*?()", "", html.strip()) + # Then we remove html comments. This has to be done before removing regular + # tags since comments can contain '>' characters. + cleaned = re.sub(r"(?s)[\n]?", "", cleaned) + # Next we can remove the remaining tags: + cleaned = re.sub(r"(?s)<.*?>", " ", cleaned) + # Finally, we deal with whitespace + cleaned = re.sub(r" ", " ", cleaned) + cleaned = re.sub(r" ", " ", cleaned) + cleaned = re.sub(r" ", " ", cleaned) + return cleaned.strip() + + def inlineRoot(xhtml): """ make root element inline """ doc = dom.parseString(xhtml) diff -r 82f9e92379b0 -r f1ba38043d78 public/libervia.css --- a/public/libervia.css Fri Feb 07 20:08:28 2014 +0100 +++ b/public/libervia.css Fri Feb 07 20:14:11 2014 +0100 @@ -581,6 +581,10 @@ text-shadow: 0 -1px 1px rgba(255,255,255,0.25); font-size: 1.2em; background-color: #eee; + font-style: italic; + font-weight: bold; + color: #666; + cursor: pointer; } .presence-button { @@ -589,20 +593,6 @@ cursor: pointer; } -.status { - font-style: italic; - font-weight: bold; - color: #666; - cursor: pointer; -} - -.status-edit { - font-style: italic; - font-weight: bold; - color: #666; - height: 25px; -} - /* RegisterBox */ .registerPanel_main button { @@ -1497,3 +1487,6 @@ .gwt-RadioButton { white-space: nowrap; } + +[contenteditable="true"] { +}