forked from nlplab/brat
-
Notifications
You must be signed in to change notification settings - Fork 1
/
htmlgen.py
212 lines (179 loc) · 6.98 KB
/
htmlgen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/usr/bin/env python
# -*- Mode: Python; tab-width: 4; indent-tabs-mode: nil; coding: utf-8; -*-
# vim:set ft=python ts=4 sw=4 sts=4 autoindent:
from __future__ import with_statement
'''
Server-side HTML generation-related functionality for
Brat Rapid Annotation Tool (brat)
'''
def escape(s):
from cgi import escape as cgi_escape
return cgi_escape(s).replace('"', '"');
def __generate_input_and_label(t, dt, keymap, indent, disabled, prefix):
l = []
# TODO: remove check once debugged; the storage form t should not
# require any sort of escaping
assert " " not in t, "INTERNAL ERROR: space in storage form"
if not disabled:
dstr = ""
else:
dstr = ' disabled="disabled"'
s = indent+' <input id="%s%s" type="radio" name="%stype" value="%s" %s/>' % (prefix, t, prefix, t, dstr)
s += '<label for="%s%s">' % (prefix, t)
if t in keymap:
# -1 if not found (i.e. key unrelated to string)
key_offset= dt.lower().find(keymap[t].lower())
else:
key_offset = -1
if key_offset == -1:
s += '%s</label>' % escape(dt)
else:
s += '%s<span class="accesskey">%s</span>%s</label>' % (escape(dt[:key_offset]), escape(dt[key_offset:key_offset+1]), escape(dt[key_offset+1:]))
l.append(s)
return l
def __generate_span_input_and_label(t, dt, keymap, indent, disabled):
return __generate_input_and_label(t, dt, keymap, indent, disabled, "span_")
def __generate_arc_input_and_label(t, dt, keymap):
return __generate_input_and_label(t, dt, keymap, "", False, "arc_")
def __generate_node_html_lines(node, keymap, projectconf, depth=0):
# TODO: make this less exceptional, avoid magic values
if node == "SEPARATOR":
return ["<hr/>"]
t = node.storage_form()
dt = projectconf.preferred_display_form(t)
# for debugging
indent = " "*6*depth
lines = []
if len(node.children) == 0:
# simple item
lines.append(indent+'<div class="item">')
lines.append(indent+' <div class="item_content">')
lines += __generate_span_input_and_label(t, dt, keymap, indent, node.unused)
lines.append(indent+' </div>')
lines.append(indent+'</div>')
else:
# collapsible item with children
lines.append(indent+'<div class="item">')
lines.append(indent+' <div class="collapser open"></div>')
lines.append(indent+' <div class="item_content">')
lines += __generate_span_input_and_label(t, dt, keymap, indent, node.unused)
lines.append(indent+' <div class="collapsible open">')
for n in node.children:
lines += __generate_node_html_lines(n, keymap, projectconf, depth+1)
lines.append(indent+' </div>')
lines.append(indent+' </div>')
lines.append(indent+'</div>')
return lines
def __generate_term_hierarchy_html(root_nodes, type_key_map, projectconf):
all_lines = []
for n in root_nodes:
all_lines += __generate_node_html_lines(n, type_key_map, projectconf)
return "\n".join(all_lines)
def generate_entity_type_html(projectconf, type_key_map):
hierarchy = projectconf.get_entity_type_hierarchy()
return __generate_term_hierarchy_html(hierarchy, type_key_map, projectconf)
def generate_event_type_html(projectconf, type_key_map):
hierarchy = projectconf.get_event_type_hierarchy()
return __generate_term_hierarchy_html(hierarchy, type_key_map, projectconf)
def generate_event_attribute_html(projectconf, type_key_map):
# TODO: proper checks of which attributes go with events;
# currently assuming all are OK.
lines = []
for t in projectconf.get_attribute_types():
lines.append("""<input id="span_mod_%s" type="checkbox" value="%s"/>""" % (t,t))
# TODO: mark accesskey as in __generate_input_and_label
lines.append("""<label for="span_mod_%s">%s</label>""" % (t,t))
return "\n".join(lines)
def generate_client_keymap(keyboard_shortcuts):
client_keymap = {}
for k in keyboard_shortcuts:
client_keymap[k] = 'span_'+keyboard_shortcuts[k]
return client_keymap
def select_keyboard_shortcuts(strings):
"""
Given a set of strings, greedily selects a shortcut key for each from
letters not previously selected. Returns a dictionary keyed by
upper-cased shortcut letters to the strings. Note that some strings
map not be in the dictionary if all their letters were previously
taken.
"""
shortcuts = {}
key_taken = {}
for s in strings:
for i in range(len(s)):
if s[i].lower() not in key_taken:
key_taken[s[i].lower()] = True
shortcuts[s[i].upper()] = s
break
return shortcuts
def generate_empty_fieldset():
return "<fieldset><legend>Type</legend>(No valid arc types)</fieldset>"
def kb_shortcuts_to_keymap(keyboard_shortcuts):
"""
Given a dictionary mapping keys (single letter) to types (any
string), returns the inverse mapping, processed for the
generate_*_html functions.
"""
type_to_key_map = {}
for k in keyboard_shortcuts:
type_to_key_map[keyboard_shortcuts[k]] = k
return type_to_key_map
def generate_arc_type_html(projectconf, types, keyboard_shortcuts):
keymap = kb_shortcuts_to_keymap(keyboard_shortcuts)
return ("<fieldset><legend>Type</legend>" +
"\n".join(["\n".join(__generate_arc_input_and_label(t, projectconf.preferred_display_form(t), keymap)) for t in types]) +
"</fieldset>")
def generate_textbound_type_html(projectconf, keyboard_shortcuts):
keymap = kb_shortcuts_to_keymap(keyboard_shortcuts)
return """<fieldset>
<legend>Entities</legend>
<fieldset>
<legend>Type</legend>
<div class="type_scroller">
""" + generate_entity_type_html(projectconf, keymap) + """
</div>
</fieldset>
</fieldset>
<fieldset>
<legend>Events</legend>
<fieldset>
<legend>Type</legend>
<div class="type_scroller">
""" + generate_event_type_html(projectconf, keymap) + """
</div>
</fieldset>
<fieldset id="span_mod_fset">
<legend>Attributes</legend>
""" + generate_event_attribute_html(projectconf, keymap) + """
</fieldset>
</fieldset>
"""
if __name__ == '__main__':
import sys
import message
from projectconfig import ProjectConfiguration
# debugging
keymap = {
'P': 'Protein',
'E': 'Entity',
'H': 'Hydroxylation',
'R': 'Dehydroxylation',
'O': 'Phosphorylation',
'S': 'Dephosphorylation',
'U': 'Ubiquitination',
'B': 'Deubiquitination',
'G': 'Glycosylation',
'L': 'Deglycosylation',
'A': 'Acetylation',
'T': 'Deacetylation',
'M': 'Methylation',
'Y': 'Demethylation',
'D': 'DNA_methylation',
'N': 'DNA_demethylation',
'C': 'Catalysis',
}
reverse_keymap = {}
for k in keymap:
reverse_keymap[keymap[k]] = k
print generate_event_type_html(ProjectConfiguration("."), reverse_keymap)
message.output_messages(sys.stdout)