comparison browser_side/base_panels.py @ 402:d7e78cb78dfc

browser_side: HTMLTextEditor and LightTextEditor factorization
author souliane <souliane@mailoo.org>
date Thu, 13 Mar 2014 16:05:35 +0100
parents ea03f898067f
children ec6f7581b453
comparison
equal deleted inserted replaced
401:ea03f898067f 402:d7e78cb78dfc
29 from pyjamas.ui.StackPanel import StackPanel 29 from pyjamas.ui.StackPanel import StackPanel
30 from pyjamas.ui.TextArea import TextArea 30 from pyjamas.ui.TextArea import TextArea
31 from pyjamas.ui.Event import BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT 31 from pyjamas.ui.Event import BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT
32 from pyjamas.ui.KeyboardListener import KEY_ENTER, KEY_ESCAPE, KeyboardHandler 32 from pyjamas.ui.KeyboardListener import KEY_ENTER, KEY_ESCAPE, KeyboardHandler
33 from pyjamas.ui.FocusListener import FocusHandler 33 from pyjamas.ui.FocusListener import FocusHandler
34 from pyjamas.ui.ClickListener import ClickHandler
34 from pyjamas import DOM 35 from pyjamas import DOM
35 36
36 from datetime import datetime 37 from datetime import datetime
37 from time import time 38 from time import time
38 39
434 """Add a method to be called whenever the text is edited. 435 """Add a method to be called whenever the text is edited.
435 @param listener: method taking two arguments: sender, keycode""" 436 @param listener: method taking two arguments: sender, keycode"""
436 self.edit_listeners.append(listener) 437 self.edit_listeners.append(listener)
437 438
438 439
439 class HTMLTextEditor(BaseTextEditor, HTML, FocusHandler, KeyboardHandler): 440 class SimpleTextEditor(BaseTextEditor, FocusHandler, KeyboardHandler, ClickHandler):
440 """Manage a simple text editor with the HTML 5 "contenteditable" property.""" 441 """Base class for manage a simple text editor."""
441 442
442 def __init__(self, content=None, modifiedCb=None, afterEditCb=None, single_line=False, enhance_display=True, listen_focus=None): 443 def __init__(self, content=None, modifiedCb=None, afterEditCb=None, single_line=False, enhance_display=True, listen_focus=None, listen_click=False):
443 """ 444 """
444 @param content 445 @param content
445 @param modifiedCb 446 @param modifiedCb
446 @param afterEditCb 447 @param afterEditCb
447 @param single_line: set to True to manage a single line editor. In that 448 @param single_line: set to True to manage a single line editor. In that
448 case the edition will be terminated when <enter> or <escape> is pressed. 449 case the edition will be terminated when <enter> or <escape> is pressed.
449 @param listen_focus: set to True to terminate the edition when the 450 @param listen_focus: set to True to terminate the edition when the
450 focus is lost. Leave to None in order to use single_line's value. 451 focus is lost. Leave to None in order to use single_line's value.
452 @param listen_click: set to True to start the edition when you click on the widget.
451 @param enhance_display: if True, the display text will be enhanced with addURLToText 453 @param enhance_display: if True, the display text will be enhanced with addURLToText
452 """ 454 """
453 HTML.__init__(self)
454 self.__single_line = single_line 455 self.__single_line = single_line
455 self.__enhance_display = enhance_display 456 self.__enhance_display = enhance_display
456 self.__listen_focus = single_line if listen_focus is None else listen_focus 457 self.__listen_focus = single_line if listen_focus is None else listen_focus
458 self.__listen_click = listen_click
457 if self.__listen_focus: 459 if self.__listen_focus:
458 FocusHandler.__init__(self) 460 FocusHandler.__init__(self)
461 if self.__listen_click:
462 ClickHandler.__init__(self)
459 KeyboardHandler.__init__(self) 463 KeyboardHandler.__init__(self)
460 strproc = lambda text: html_sanitize(html_strip(text)) if self.__single_line else html_strip(text) 464 strproc = lambda text: html_sanitize(html_strip(text)) if self.__single_line else html_strip(text)
461 BaseTextEditor.__init__(self, content, strproc, modifiedCb, afterEditCb) 465 BaseTextEditor.__init__(self, content, strproc, modifiedCb, afterEditCb)
466 self.textarea = self.display = None
462 467
463 def setContent(self, content=None): 468 def setContent(self, content=None):
464 BaseTextEditor.setContent(self, content) 469 BaseTextEditor.setContent(self, content)
465 470
466 def getContent(self): 471 def getContent(self):
467 text = DOM.getInnerHTML(self.getElement()) 472 raise NotImplementedError
468 return {'text': self.strproc(text) if text else ''}
469 473
470 def edit(self, edit, abort=False, sync=False): 474 def edit(self, edit, abort=False, sync=False):
471 if edit:
472 self.setHTML(self._original_content['text'])
473 self.getElement().setAttribute('contenteditable', 'true' if edit else 'false')
474 BaseTextEditor.edit(self, edit) 475 BaseTextEditor.edit(self, edit)
475 if edit: 476 if edit:
476 if self.__listen_focus: 477 if self.__listen_focus and self not in self.textarea._focusListeners:
477 self.addFocusListener(self) 478 self.textarea.addFocusListener(self)
478 self.addKeyboardListener(self) 479 if self.__listen_click:
480 self.display.clearClickListener()
481 if self not in self.textarea._keyboardListeners:
482 self.textarea.addKeyboardListener(self)
479 else: 483 else:
480 self.setDisplayContent() 484 self.setDisplayContent()
481 if self.__listen_focus: 485 if self.__listen_focus:
482 if self in self._focusListeners: 486 try:
483 self.removeFocusListener(self)
484 if self in self._keyboardListeners:
485 self.removeKeyboardListener(self)
486
487 def setDisplayContent(self):
488 text = addURLToImage(self._original_content['text'])
489 self.setHTML(addURLToText(text) if self.__enhance_display else text)
490
491 def setFocus(self, focus):
492 if focus:
493 self.getElement().focus()
494 else:
495 self.getElement().blur()
496
497 def onKeyDown(self, sender, keycode, modifiers):
498 for listener in self.edit_listeners:
499 listener(self, keycode)
500
501 def onKeyPress(self, sender, keycode, modifiers):
502 if not self.__single_line:
503 return
504 # XXX: it seems that pyjamas never catches the escape key
505 if keycode in (KEY_ENTER, KEY_ESCAPE): # finish the edition
506 self.setFocus(False)
507 if not self.__listen_focus:
508 self.edit(False)
509
510 def onLostFocus(self, sender):
511 """Finish the edition when focus is lost"""
512 self.edit(False)
513
514
515 class LightTextEditor(BaseTextEditor, SimplePanel, FocusHandler, KeyboardHandler):
516 """Manage a simple text editor with a TextArea for editing, HTML for display."""
517
518 def __init__(self, content=None, modifiedCb=None, afterEditCb=None, single_line=False, enhance_display=True, listen_focus=None):
519 """
520 @param content
521 @param modifiedCb
522 @param afterEditCb
523 @param single_line: set to True to manage a single line editor. In that
524 case the edition will be terminated when <enter> or <escape> is pressed.
525 @param listen_focus: set to True to terminate the edition when the
526 focus is lost. Leave to None in order to use single_line's value.
527 @param enhance_display: if True, the display text will be enhanced with addURLToText
528 """
529 SimplePanel.__init__(self)
530 self.__single_line = single_line
531 self.__enhance_display = enhance_display
532 self.__listen_focus = single_line if listen_focus is None else listen_focus
533 if self.__listen_focus:
534 FocusHandler.__init__(self)
535 KeyboardHandler.__init__(self)
536 strproc = lambda text: html_sanitize(html_strip(text)) if self.__single_line else html_strip(text)
537 BaseTextEditor.__init__(self, content, strproc, modifiedCb, afterEditCb)
538 self.textarea = TextArea()
539 self.display = HTML()
540
541 def setContent(self, content=None):
542 BaseTextEditor.setContent(self, content)
543
544 def getContent(self):
545 text = self.textarea.getText()
546 return {'text': self.strproc(text) if text else ''}
547
548 def edit(self, edit, abort=False, sync=False):
549 if edit:
550 self.textarea.setText(self._original_content['text'])
551 self.setWidget(self.textarea if edit else self.display)
552 BaseTextEditor.edit(self, edit)
553 if edit:
554 if self.__listen_focus:
555 self.textarea.addFocusListener(self)
556 self.textarea.addKeyboardListener(self)
557 else:
558 self.setDisplayContent()
559 if self.__listen_focus:
560 if self in self._focusListeners:
561 self.textarea.removeFocusListener(self) 487 self.textarea.removeFocusListener(self)
562 if self in self._keyboardListeners: 488 except ValueError:
489 pass
490 if self.__listen_click and self not in self.display._clickListeners:
491 self.display.addClickListener(self)
492 try:
563 self.textarea.removeKeyboardListener(self) 493 self.textarea.removeKeyboardListener(self)
494 except ValueError:
495 pass
564 496
565 def setDisplayContent(self): 497 def setDisplayContent(self):
566 text = addURLToImage(self._original_content['text']) 498 text = addURLToImage(self._original_content['text'])
567 self.display.setHTML(addURLToText(text) if self.__enhance_display else text) 499 self.display.setHTML(addURLToText(text) if self.__enhance_display else text)
568 500
569 def setFocus(self, focus): 501 def setFocus(self, focus):
570 self.textarea.setFocus(focus) 502 raise NotImplementedError
571 503
572 def onKeyDown(self, sender, keycode, modifiers): 504 def onKeyDown(self, sender, keycode, modifiers):
573 for listener in self.edit_listeners: 505 for listener in self.edit_listeners:
574 listener(self.textarea, keycode) 506 listener(self.textarea, keycode)
575 507
582 if not self.__listen_focus: 514 if not self.__listen_focus:
583 self.edit(False) 515 self.edit(False)
584 516
585 def onLostFocus(self, sender): 517 def onLostFocus(self, sender):
586 """Finish the edition when focus is lost""" 518 """Finish the edition when focus is lost"""
587 self.edit(False) 519 if self.__listen_focus:
520 self.edit(False)
521
522 def onClick(self, sender=None):
523 """Start the edition when the widget is clicked"""
524 if self.__listen_click:
525 self.edit(True)
526
527 def onBrowserEvent(self, event):
528 if self.__listen_focus:
529 FocusHandler.onBrowserEvent(self, event)
530 if self.__listen_click:
531 ClickHandler.onBrowserEvent(self, event)
532 KeyboardHandler.onBrowserEvent(self, event)
533
534
535 class HTMLTextEditor(SimpleTextEditor, HTML, FocusHandler, KeyboardHandler):
536 """Manage a simple text editor with the HTML 5 "contenteditable" property."""
537
538 def __init__(self, content=None, modifiedCb=None, afterEditCb=None, single_line=False, enhance_display=True, listen_focus=None, listen_click=False):
539 HTML.__init__(self)
540 SimpleTextEditor.__init__(self, content, modifiedCb, afterEditCb, single_line, enhance_display, listen_focus, listen_click)
541 self.textarea = self.display = self
542
543 def getContent(self):
544 text = DOM.getInnerHTML(self.getElement())
545 return {'text': self.strproc(text) if text else ''}
546
547 def edit(self, edit, abort=False, sync=False):
548 if edit:
549 self.textarea.setHTML(self._original_content['text'])
550 self.getElement().setAttribute('contenteditable', 'true' if edit else 'false')
551 SimpleTextEditor.edit(self, edit, abort, sync)
552
553 def setFocus(self, focus):
554 if focus:
555 self.getElement().focus()
556 else:
557 self.getElement().blur()
558
559
560 class LightTextEditor(SimpleTextEditor, SimplePanel, FocusHandler, KeyboardHandler):
561 """Manage a simple text editor with a TextArea for editing, HTML for display."""
562
563 def __init__(self, content=None, modifiedCb=None, afterEditCb=None, single_line=False, enhance_display=True, listen_focus=None, listen_click=False):
564 SimplePanel.__init__(self)
565 SimpleTextEditor.__init__(self, content, modifiedCb, afterEditCb, single_line, enhance_display, listen_focus, listen_click)
566 self.textarea = TextArea()
567 self.display = HTML()
568
569 def getContent(self):
570 text = self.textarea.getText()
571 return {'text': self.strproc(text) if text else ''}
572
573 def edit(self, edit, abort=False, sync=False):
574 if edit:
575 self.textarea.setText(self._original_content['text'])
576 self.setWidget(self.textarea if edit else self.display)
577 SimpleTextEditor.edit(self, edit, abort, sync)
578
579 def setFocus(self, focus):
580 self.textarea.setFocus(focus)