Fixed StyledTextTagType to match grampstype; fixed _DEFAULT on all types; editing notes on web not quite correct (error in DocBackend?)

svn: r19695
This commit is contained in:
Doug Blank 2012-05-29 13:39:55 +00:00
parent a8f5d1f8e1
commit abbb02a08e
7 changed files with 180 additions and 83 deletions

View File

@ -9,12 +9,13 @@
$('.wysiwyg').htmlarea({ $('.wysiwyg').htmlarea({
toolbar: [ toolbar: [
"bold", "italic", "underline", "bold", "italic", "underline",
"|", "forecolor", "|", "forecolor", "superscript",
"|", "link", "unlink", "|", "link", "unlink",
"|", "html" "|", "html"
] ]
}); });
// FIXME: easier way? // FIXME: add font, fontsize, backcolor
// FIXME: find easier way:
$('.jHtmlArea').contents().find('iframe').contents().find('body').css({"background-color": "white"}); $('.jHtmlArea').contents().find('iframe').contents().find('body').css({"background-color": "white"});
}); });
function setnotetext() { function setnotetext() {

View File

@ -63,11 +63,17 @@ def get_type(the_type, data, get_or_create=False):
def get_default_type(the_type): def get_default_type(the_type):
""" """
Gets the default row for a given Type. Gets the default database object for a given GrampsType.
""" """
val, name = the_type._DEFAULT val, name = the_type._DEFAULT
return the_type.objects.get(val=val, name=name) return the_type.objects.get(val=val, name=name)
def get_default_type_value(the_type):
"""
Gets the default value for a given gen.lib.GrampsType.
"""
return [x for x in the_type._DATAMAP if x[0] == the_type._DEFAULT][0]
def get_datamap(grampsclass): def get_datamap(grampsclass):
return sorted([(x[0],x[2]) for x in grampsclass._DATAMAP], return sorted([(x[0],x[2]) for x in grampsclass._DATAMAP],
key=lambda item: item[1]) key=lambda item: item[1])
@ -97,7 +103,7 @@ class mGrampsType(models.Model):
def get_default_type(self): def get_default_type(self):
""" return a tuple default (val,name) """ """ return a tuple default (val,name) """
return self._DATAMAP[self._DEFAULT] return self._DEFAULT
def __len__(self): def __len__(self):
""" For use as a sequence for getting (val, name) """ """ For use as a sequence for getting (val, name) """
@ -116,35 +122,35 @@ class NameType(mGrampsType):
from gen.lib.nametype import NameType from gen.lib.nametype import NameType
_DATAMAP = get_datamap(NameType) _DATAMAP = get_datamap(NameType)
_CUSTOM = NameType._CUSTOM _CUSTOM = NameType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == NameType._DEFAULT][0] _DEFAULT = get_default_type_value(NameType)
val = models.IntegerField('name type', choices=_DATAMAP, blank=False) val = models.IntegerField('name type', choices=_DATAMAP, blank=False)
class NameOriginType(mGrampsType): class NameOriginType(mGrampsType):
from gen.lib.nameorigintype import NameOriginType from gen.lib.nameorigintype import NameOriginType
_DATAMAP = get_datamap(NameOriginType) _DATAMAP = get_datamap(NameOriginType)
_CUSTOM = NameOriginType._CUSTOM _CUSTOM = NameOriginType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == NameOriginType._DEFAULT][0] _DEFAULT = get_default_type_value(NameOriginType)
val = models.IntegerField('name origin type', choices=_DATAMAP, blank=False) val = models.IntegerField('name origin type', choices=_DATAMAP, blank=False)
class AttributeType(mGrampsType): class AttributeType(mGrampsType):
from gen.lib.attrtype import AttributeType from gen.lib.attrtype import AttributeType
_DATAMAP = get_datamap(AttributeType) _DATAMAP = get_datamap(AttributeType)
_CUSTOM = AttributeType._CUSTOM _CUSTOM = AttributeType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == AttributeType._DEFAULT][0] _DEFAULT = get_default_type_value(AttributeType)
val = models.IntegerField('attribute type', choices=_DATAMAP, blank=False) val = models.IntegerField('attribute type', choices=_DATAMAP, blank=False)
class UrlType(mGrampsType): class UrlType(mGrampsType):
from gen.lib.urltype import UrlType from gen.lib.urltype import UrlType
_DATAMAP = get_datamap(UrlType) _DATAMAP = get_datamap(UrlType)
_CUSTOM = UrlType._CUSTOM _CUSTOM = UrlType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == UrlType._DEFAULT][0] _DEFAULT = get_default_type_value(UrlType)
val = models.IntegerField('url type', choices=_DATAMAP, blank=False) val = models.IntegerField('url type', choices=_DATAMAP, blank=False)
class ChildRefType(mGrampsType): class ChildRefType(mGrampsType):
from gen.lib.childreftype import ChildRefType from gen.lib.childreftype import ChildRefType
_DATAMAP = get_datamap(ChildRefType) _DATAMAP = get_datamap(ChildRefType)
_CUSTOM = ChildRefType._CUSTOM _CUSTOM = ChildRefType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == ChildRefType._DEFAULT][0] _DEFAULT = get_default_type_value(ChildRefType)
val = models.IntegerField('child reference type', choices=_DATAMAP, val = models.IntegerField('child reference type', choices=_DATAMAP,
blank=False) blank=False)
@ -152,14 +158,14 @@ class RepositoryType(mGrampsType):
from gen.lib.repotype import RepositoryType from gen.lib.repotype import RepositoryType
_DATAMAP = get_datamap(RepositoryType) _DATAMAP = get_datamap(RepositoryType)
_CUSTOM = RepositoryType._CUSTOM _CUSTOM = RepositoryType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == RepositoryType._DEFAULT][0] _DEFAULT = get_default_type_value(RepositoryType)
val = models.IntegerField('repository type', choices=_DATAMAP, blank=False) val = models.IntegerField('repository type', choices=_DATAMAP, blank=False)
class EventType(mGrampsType): class EventType(mGrampsType):
from gen.lib.eventtype import EventType from gen.lib.eventtype import EventType
_DATAMAP = get_datamap(EventType) _DATAMAP = get_datamap(EventType)
_CUSTOM = EventType._CUSTOM _CUSTOM = EventType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == EventType._DEFAULT][0] _DEFAULT = get_default_type_value(EventType)
BIRTH = 12 BIRTH = 12
DEATH = 13 DEATH = 13
val = models.IntegerField('event type', choices=_DATAMAP, blank=False) val = models.IntegerField('event type', choices=_DATAMAP, blank=False)
@ -168,7 +174,7 @@ class FamilyRelType(mGrampsType):
from gen.lib.familyreltype import FamilyRelType from gen.lib.familyreltype import FamilyRelType
_DATAMAP = get_datamap(FamilyRelType) _DATAMAP = get_datamap(FamilyRelType)
_CUSTOM = FamilyRelType._CUSTOM _CUSTOM = FamilyRelType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == FamilyRelType._DEFAULT][0] _DEFAULT = get_default_type_value(FamilyRelType)
val = models.IntegerField('family relation type', choices=_DATAMAP, val = models.IntegerField('family relation type', choices=_DATAMAP,
blank=False) blank=False)
@ -176,7 +182,7 @@ class SourceMediaType(mGrampsType):
from gen.lib.srcmediatype import SourceMediaType from gen.lib.srcmediatype import SourceMediaType
_DATAMAP = get_datamap(SourceMediaType) _DATAMAP = get_datamap(SourceMediaType)
_CUSTOM = SourceMediaType._CUSTOM _CUSTOM = SourceMediaType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == SourceMediaType._DEFAULT][0] _DEFAULT = get_default_type_value(SourceMediaType)
val = models.IntegerField('source medium type', choices=_DATAMAP, val = models.IntegerField('source medium type', choices=_DATAMAP,
blank=False) blank=False)
@ -184,22 +190,22 @@ class EventRoleType(mGrampsType):
from gen.lib.eventroletype import EventRoleType from gen.lib.eventroletype import EventRoleType
_DATAMAP = get_datamap(EventRoleType) _DATAMAP = get_datamap(EventRoleType)
_CUSTOM = EventRoleType._CUSTOM _CUSTOM = EventRoleType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == EventRoleType._DEFAULT][0] _DEFAULT = get_default_type_value(EventRoleType)
val = models.IntegerField('event role type', choices=_DATAMAP, blank=False) val = models.IntegerField('event role type', choices=_DATAMAP, blank=False)
class NoteType(mGrampsType): class NoteType(mGrampsType):
from gen.lib.notetype import NoteType from gen.lib.notetype import NoteType
_DATAMAP = get_datamap(NoteType) _DATAMAP = get_datamap(NoteType)
_CUSTOM = NoteType._CUSTOM _CUSTOM = NoteType._CUSTOM
_DEFAULT = [x for x in _DATAMAP if x[0] == NoteType._DEFAULT][0] _DEFAULT = get_default_type_value(NoteType)
val = models.IntegerField('note type', choices=_DATAMAP, blank=False) val = models.IntegerField('note type', choices=_DATAMAP, blank=False)
class MarkupType(mGrampsType): class StyledTextTagType(mGrampsType):
from gen.lib.notetype import NoteType from gen.lib.styledtexttagtype import StyledTextTagType
_DATAMAP = [(0, "Custom")] _DATAMAP = get_datamap(StyledTextTagType)
_CUSTOM = 0 _CUSTOM = None
_DEFAULT = _DATAMAP[0] _DEFAULT = None
val = models.IntegerField('note type', choices=_DATAMAP, blank=False) val = models.IntegerField('styled text tag type', choices=_DATAMAP, blank=False)
class GenderType(mGrampsType): class GenderType(mGrampsType):
_DATAMAP = [(2, 'Unknown'), (1, 'Male'), (0, 'Female')] _DATAMAP = [(2, 'Unknown'), (1, 'Male'), (0, 'Female')]
@ -716,7 +722,7 @@ class Lds(DateObject, SecondaryObject):
class Markup(models.Model): class Markup(models.Model):
note = models.ForeignKey('Note') note = models.ForeignKey('Note')
markup_type = models.ForeignKey('MarkupType') styled_text_tag_type = models.ForeignKey('StyledTextTagType')
order = models.PositiveIntegerField() order = models.PositiveIntegerField()
string = models.TextField(blank=True, null=True) string = models.TextField(blank=True, null=True)
start_stop_list = models.TextField(default="[]") start_stop_list = models.TextField(default="[]")
@ -891,6 +897,7 @@ TABLES = [
("type", LdsType), ("type", LdsType),
("type", LdsStatus), ("type", LdsStatus),
("type", ThemeType), ("type", ThemeType),
("type", StyledTextTagType),
("abstract", DateObject), ("abstract", DateObject),
("abstract", PrimaryObject), ("abstract", PrimaryObject),
("primary", Person), ("primary", Person),

View File

@ -22,7 +22,7 @@
""" Views for Person, Name, and Surname """ """ Views for Person, Name, and Surname """
## Gramps Modules ## Gramps Modules
from webapp.utils import _, boolean, update_last_changed, StyledNoteFormatter from webapp.utils import _, boolean, update_last_changed, StyledNoteFormatter, parse_styled_text
from webapp.grampsdb.models import Note from webapp.grampsdb.models import Note
from webapp.grampsdb.forms import * from webapp.grampsdb.forms import *
from webapp.libdjango import DjangoInterface from webapp.libdjango import DjangoInterface
@ -65,14 +65,15 @@ def process_note(request, context, handle, action, add_to=None): # view, edit, s
noteform.model = note noteform.model = note
elif action == "save": elif action == "save":
note = Note.objects.get(handle=handle) note = Note.objects.get(handle=handle)
genlibnote = db.get_note_from_handle(note.handle) notetext = ""
notetext = snf.format(genlibnote) # FIXME
noteform = NoteForm(request.POST, instance=note, initial={"notetext": notetext}) noteform = NoteForm(request.POST, instance=note, initial={"notetext": notetext})
noteform.model = note noteform.model = note
#note.text = noteform.data["notetext"] # FIXME: split text and tags
if noteform.is_valid(): if noteform.is_valid():
update_last_changed(note, request.user.username) update_last_changed(note, request.user.username)
notedata = parse_styled_text(noteform.data["notetext"])
note.text = notedata[0]
note = noteform.save() note = noteform.save()
dji.save_note_markup(note, notedata[1])
dji.rebuild_cache(note) dji.rebuild_cache(note)
notetext = noteform.data["notetext"] notetext = noteform.data["notetext"]
action = "view" action = "view"
@ -81,13 +82,15 @@ def process_note(request, context, handle, action, add_to=None): # view, edit, s
action = "edit" action = "edit"
elif action == "create": elif action == "create":
note = Note(handle=create_id()) note = Note(handle=create_id())
notetext = "" # FIXME notetext = ""
noteform = NoteForm(request.POST, instance=note, initial={"notetext": notetext}) noteform = NoteForm(request.POST, instance=note, initial={"notetext": notetext})
noteform.model = note noteform.model = note
#note.text = noteform.data["notetext"] # FIXME: split text and tags
if noteform.is_valid(): if noteform.is_valid():
update_last_changed(note, request.user.username) update_last_changed(note, request.user.username)
notedata = parse_styled_text(noteform.data["notetext"])
note.text = notedata[0]
note = noteform.save() note = noteform.save()
dji.save_note_markup(note, notedata[1])
dji.rebuild_cache(note) dji.rebuild_cache(note)
if add_to: if add_to:
item, handle = add_to item, handle = add_to

View File

@ -42,6 +42,7 @@ from gen.lib.familyreltype import FamilyRelType
from gen.lib.srcmediatype import SourceMediaType from gen.lib.srcmediatype import SourceMediaType
from gen.lib.eventroletype import EventRoleType from gen.lib.eventroletype import EventRoleType
from gen.lib.notetype import NoteType from gen.lib.notetype import NoteType
from gen.lib.styledtexttagtype import StyledTextTagType
from grampsdb.models import (GenderType, LdsType, LdsStatus, from grampsdb.models import (GenderType, LdsType, LdsStatus,
NameFormatType, NameOriginType, ThemeType) NameFormatType, NameOriginType, ThemeType)
@ -61,7 +62,7 @@ for table, entries in [("grampsdb.config",
(("setting", "\"db_version\""), (("setting", "\"db_version\""),
("description", "\"database scheme version\""), ("description", "\"database scheme version\""),
("value_type", "\"str\""), ("value_type", "\"str\""),
("value", "\"0.5.1\"")), ("value", "\"0.6.0\"")),
(("setting", "\"db_created\""), (("setting", "\"db_created\""),
("description", "\"database creation date/time\""), ("description", "\"database creation date/time\""),
("value_type", "\"str\""), ("value_type", "\"str\""),
@ -174,7 +175,7 @@ for table, entries in [("grampsdb.config",
type_models = [NameType, NameOriginType, AttributeType, UrlType, ChildRefType, type_models = [NameType, NameOriginType, AttributeType, UrlType, ChildRefType,
RepositoryType, EventType, FamilyRelType, SourceMediaType, RepositoryType, EventType, FamilyRelType, SourceMediaType,
EventRoleType, NoteType, GenderType, LdsType, LdsStatus, EventRoleType, NoteType, GenderType, LdsType, LdsStatus,
NameFormatType] NameFormatType, StyledTextTagType]
for type in type_models: for type in type_models:
count = 1 count = 1
# Add each code: # Add each code:

View File

@ -299,14 +299,13 @@ class DjangoInterface(object):
retval = [] retval = []
markups = models.Markup.objects.filter(note=note).order_by("order") markups = models.Markup.objects.filter(note=note).order_by("order")
for markup in markups: for markup in markups:
# FIXME: not all of these are strings; bummer
if markup.string and markup.string.isdigit(): if markup.string and markup.string.isdigit():
value = int(markup.string) value = int(markup.string)
else: else:
value = markup.string value = markup.string
start_stop_list = markup.start_stop_list start_stop_list = markup.start_stop_list
ss_list = eval(start_stop_list) ss_list = eval(start_stop_list)
retval += [(tuple(markup.markup_type), value, ss_list)] retval += [(tuple(markup.styled_text_tag_type), value, ss_list)]
return retval return retval
def get_note(self, note): def get_note(self, note):
@ -1257,12 +1256,14 @@ class DjangoInterface(object):
count = 1 count = 1
for markup in markup_list: for markup in markup_list:
markup_code, value, start_stop_list = markup markup_code, value, start_stop_list = markup
m = models.Markup(note=note, order=count, m = models.Markup(
markup_type=models.get_type(models.MarkupType, note=note,
markup_code, order=count,
get_or_create=True), styled_text_tag_type=models.get_type(models.StyledTextTagType,
string=value, markup_code,
start_stop_list=str(start_stop_list)) get_or_create=False),
string=value,
start_stop_list=str(start_stop_list))
m.save() m.save()
def add_note(self, data): def add_note(self, data):

View File

@ -30,7 +30,7 @@ dp = parser.parse
# "/home/dblank/gramps/trunk/example/gramps/data.gramps", # "/home/dblank/gramps/trunk/example/gramps/data.gramps",
# cli.user.User()) # cli.user.User())
from webapp.utils import StyledNoteFormatter from webapp.utils import StyledNoteFormatter, parse_styled_text
snf = StyledNoteFormatter(db) snf = StyledNoteFormatter(db)
#for n in Note.objects.all(): #for n in Note.objects.all():
# note = db.get_note_from_handle(n.handle) # note = db.get_note_from_handle(n.handle)
@ -38,5 +38,9 @@ snf = StyledNoteFormatter(db)
note = Note.objects.get(handle="aef30789d3d2090abe2") note = Note.objects.get(handle="aef30789d3d2090abe2")
genlibnote = db.get_note_from_handle(note.handle) genlibnote = db.get_note_from_handle(note.handle)
print snf.format(genlibnote) html_text = snf.format(genlibnote)
#st = gen.lib.StyledText(note.text, dji.get_note_markup(note)) # FIXME: this looks wrong:
#print html_text
#print parse_styled_text(html_text)
##st = gen.lib.StyledText(note.text, dji.get_note_markup(note))

View File

@ -28,7 +28,9 @@
#------------------------------------------------------------------------ #------------------------------------------------------------------------
import locale import locale
import sys import sys
import re
import datetime import datetime
from HTMLParser import HTMLParser
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -744,6 +746,7 @@ class WebAppBackend(HtmlBackend):
DocBackend.FONTFACE, DocBackend.FONTFACE,
DocBackend.FONTSIZE, DocBackend.FONTSIZE,
DocBackend.FONTCOLOR, DocBackend.FONTCOLOR,
DocBackend.SUPERSCRIPT,
DocBackend.LINK, DocBackend.LINK,
] ]
@ -751,6 +754,7 @@ class WebAppBackend(HtmlBackend):
DocBackend.BOLD : ("<b>", "</b>"), DocBackend.BOLD : ("<b>", "</b>"),
DocBackend.ITALIC : ("<i>", "</i>"), DocBackend.ITALIC : ("<i>", "</i>"),
DocBackend.UNDERLINE : ('<u>', '</u>'), DocBackend.UNDERLINE : ('<u>', '</u>'),
DocBackend.SUPERSCRIPT : ("<sup>", "</sup>"),
} }
### Taken from Narrated Web Report ### Taken from Narrated Web Report
@ -761,53 +765,15 @@ class StyledNoteFormatter(object):
self._backend.build_link = self.build_link self._backend.build_link = self.build_link
def format(self, note): def format(self, note):
return self.styled_note( return self.styled_note(note.get_styledtext())
note.get_styledtext(),
note.get_format(),
contains_html=(note.get_type() == gen.lib.NoteType.HTML_CODE))
def styled_note(self, styledtext, format, contains_html=False): def styled_note(self, styledtext):
"""
styledtext : assumed a StyledText object to write
format : = 0 : Flowed, = 1 : Preformatted
style_name : name of the style to use for default presentation
"""
text = str(styledtext) text = str(styledtext)
if not text: if not text:
return '' return ''
s_tags = styledtext.get_tags() s_tags = styledtext.get_tags()
markuptext = self._backend.add_markup_from_styled(text, s_tags, markuptext = self._backend.add_markup_from_styled(text, s_tags, split='\n').replace("\n", "<br/>")
split='\n') return markuptext
htmllist = Html("div") #"div", class_="grampsstylednote")
if contains_html:
htmllist += text
else:
linelist = []
linenb = 1
for line in markuptext.split('\n'):
[line, sigcount] = process_spaces(line, format)
if sigcount == 0:
# The rendering of an empty paragraph '<p></p>'
# is undefined so we use a non-breaking space
if linenb == 1:
linelist.append('&nbsp;')
htmllist.extend(Html('p') + linelist)
linelist = []
linenb = 1
else:
if linenb > 1:
linelist[-1] += '<br />'
linelist.append(line)
linenb += 1
if linenb > 1:
htmllist.extend(Html('p') + linelist)
# if the last line was blank, then as well as outputting the previous para,
# which we have just done,
# we also output a new blank para
if sigcount == 0:
linelist = ["&nbsp;"]
htmllist.extend(Html('p') + linelist)
return "".join(htmllist)
def build_link(self, prop, handle, obj_class): def build_link(self, prop, handle, obj_class):
""" """
@ -826,3 +792,117 @@ class StyledNoteFormatter(object):
"in table name '%s'" % obj_class) "in table name '%s'" % obj_class)
# handle, ppl # handle, ppl
return "/%s/%s" % (obj_class.lower(), handle) return "/%s/%s" % (obj_class.lower(), handle)
class WebAppParser(HTMLParser):
BOLD = 0
ITALIC = 1
UNDERLINE = 2
FONTFACE = 3
FONTSIZE = 4
FONTCOLOR = 5
HIGHLIGHT = 6
SUPERSCRIPT = 7
LINK = 8
def __init__(self):
HTMLParser.__init__(self)
self.__text = ""
self.__tags = {}
self.__stack = []
def handle_data(self, data):
self.__text += data
def push(self, pos, tag, attrs):
self.__stack.append([pos, tag, attrs])
def pop(self):
return self.__stack.pop()
def handle_starttag(self, tag, attrs):
self.push(len(self.__text), tag.lower(), attrs)
def handle_endtag(self, tag):
tag = tag.lower()
(start_pos, start_tag, attrs) = self.pop()
attrs = {x[0]: x[1] for x in attrs}
if tag != start_tag: return # skip <i><b></i></b> formats
arg = None
tagtype = None
if tag == "span":
# "span": get color, font, size
if "style" in attrs:
style = attrs["style"]
if 'color' in style:
tagtype = self.FONTCOLOR
match = re.match("color:([^;]*);", style)
if match:
arg = match.groups()[0]
else:
print "Unhandled color tag: '%s'" % style
elif "font-family" in style:
tagtype = self.FONTFACE
match = re.match("font-family:'([^;]*)';", style)
if match:
arg = match.groups()[0]
else:
print "Unhandled font-family tag: '%s'" % style
elif "font-size" in style:
tagtype = self.FONTSIZE
match = re.match("font-size:([^;]*)px;", style)
if match:
arg = int(match.groups()[0])
else:
print "Unhandled font-size tag: '%s'" % style
else:
print "Unhandled span arg: '%s'" % attrs
else:
print "span has no style: '%s'" % attrs
# "b", "i", "u", "sup": direct conversion
elif tag == "b":
tagtype = self.BOLD
elif tag == "i":
tagtype = self.ITALIC
elif tag == "u":
tagtype = self.UNDERLINE
elif tag == "sup":
tagtype = self.SUPERSCRIPT
elif tag == "br":
self.__text += "\n"
return
elif tag == "p":
self.__text += "\n\n"
return
elif tag == "a":
tagtype = self.LINK
# "a": get /object/handle, or url
if "href" in attrs:
href = attrs["href"]
if href.startswith("/"):
parts = href.split("/")
arg = "gramps://%s/handle/%s" % (parts[-2].title(), parts[-1])
else:
arg = href
else:
print "Unhandled a with no href: '%s'" % attrs
else:
return
print "Unhandled tag: '%s'" % tag
key = ((tagtype, u''), arg)
if key not in self.__tags:
self.__tags[key] = []
self.__tags[key].append((start_pos, len(self.__text)))
def tags(self):
# [((code, u''), string/num, [(start, stop), ...]), ...]
return [(key[0], key[1], self.__tags[key]) for key in self.__tags]
def text(self):
return self.__text
def parse_styled_text(text):
parser = WebAppParser()
parser.feed(text)
parser.close()
return (parser.text(), parser.tags())