104 """replace <ref rql=''> links by <a href="...">""" |
104 """replace <ref rql=''> links by <a href="...">""" |
105 if not text: |
105 if not text: |
106 return u'' |
106 return u'' |
107 return REF_PROG.sub(lambda obj, view=view:_subst_rql(view, obj), text) |
107 return REF_PROG.sub(lambda obj, view=view:_subst_rql(view, obj), text) |
108 |
108 |
|
109 # fallback implementation, nicer one defined below if lxml is available |
|
110 def soup2xhtml(data, encoding): |
|
111 return data |
|
112 |
|
113 # fallback implementation, nicer one defined below if lxml> 2.0 is available |
|
114 def safe_cut(text, length): |
|
115 """returns a string of length <length> based on <text>, removing any html |
|
116 tags from given text if cut is necessary.""" |
|
117 if text is None: |
|
118 return u'' |
|
119 text_nohtml = remove_html_tags(text) |
|
120 # try to keep html tags if text is short enough |
|
121 if len(text_nohtml) <= length: |
|
122 return text |
|
123 # else if un-tagged text is too long, cut it |
|
124 return text_nohtml[:length-3] + u'...' |
|
125 |
|
126 |
109 try: |
127 try: |
110 from lxml import etree |
128 from lxml import etree |
111 etree.HTML('<div>test</div>').iter |
|
112 except (ImportError, AttributeError): |
129 except (ImportError, AttributeError): |
113 # gae environment: lxml not availabel |
130 # gae environment: lxml not availabel |
114 |
131 pass |
115 def soup2xhtml(data, encoding): |
|
116 return data |
|
117 |
|
118 def safe_cut(text, length): |
|
119 """returns a string of length <length> based on <text>, removing any html |
|
120 tags from given text if cut is necessary.""" |
|
121 if text is None: |
|
122 return u'' |
|
123 text_nohtml = remove_html_tags(text) |
|
124 # try to keep html tags if text is short enough |
|
125 if len(text_nohtml) <= length: |
|
126 return text |
|
127 # else if un-tagged text is too long, cut it |
|
128 return text_nohtml[:length-3] + u'...' |
|
129 |
|
130 else: |
132 else: |
131 |
133 |
132 def soup2xhtml(data, encoding): |
134 def soup2xhtml(data, encoding): |
133 """tidy (at least try) html soup and return the result |
135 """tidy (at least try) html soup and return the result |
134 Note: the function considers a string with no surrounding tag as valid |
136 Note: the function considers a string with no surrounding tag as valid |
140 # why we specify an encoding and re-decode to unicode later |
142 # why we specify an encoding and re-decode to unicode later |
141 body = etree.tostring(xmltree[0], encoding=encoding) |
143 body = etree.tostring(xmltree[0], encoding=encoding) |
142 # remove <body> and </body> and decode to unicode |
144 # remove <body> and </body> and decode to unicode |
143 return body[11:-13].decode(encoding) |
145 return body[11:-13].decode(encoding) |
144 |
146 |
145 def safe_cut(text, length): |
147 if hasattr(etree.HTML('<div>test</div>'), 'iter'): |
146 """returns an html document of length <length> based on <text>, |
148 |
147 and cut is necessary. |
149 def safe_cut(text, length): |
148 """ |
150 """returns an html document of length <length> based on <text>, |
149 if text is None: |
151 and cut is necessary. |
150 return u'' |
152 """ |
151 textParse = etree.HTML(text) |
153 if text is None: |
152 compteur = 0 |
154 return u'' |
153 |
155 textParse = etree.HTML(text) |
154 for element in textParse.iter(): |
156 compteur = 0 |
155 if compteur > length: |
157 |
156 parent = element.getparent() |
158 for element in textParse.iter(): |
157 parent.remove(element) |
159 if compteur > length: |
158 else: |
160 parent = element.getparent() |
159 if element.text is not None: |
161 parent.remove(element) |
160 text_resum = text_cut_letters(element.text,length) |
162 else: |
161 len_text_resum = len(''.join(text_resum.split())) |
163 if element.text is not None: |
162 compteur = compteur + len_text_resum |
164 text_resum = text_cut_letters(element.text,length) |
163 element.text = text_resum |
|
164 |
|
165 if element.tail is not None: |
|
166 if compteur < length: |
|
167 text_resum = text_cut_letters(element.tail,length) |
|
168 len_text_resum = len(''.join(text_resum.split())) |
165 len_text_resum = len(''.join(text_resum.split())) |
169 compteur = compteur + len_text_resum |
166 compteur = compteur + len_text_resum |
170 element.tail = text_resum |
167 element.text = text_resum |
171 else: |
168 |
172 element.tail = '' |
169 if element.tail is not None: |
173 |
170 if compteur < length: |
174 div = etree.HTML('<div></div>')[0][0] |
171 text_resum = text_cut_letters(element.tail,length) |
175 listNode = textParse[0].getchildren() |
172 len_text_resum = len(''.join(text_resum.split())) |
176 for node in listNode: |
173 compteur = compteur + len_text_resum |
177 div.append(deepcopy(node)) |
174 element.tail = text_resum |
178 return etree.tounicode(div) |
175 else: |
|
176 element.tail = '' |
|
177 |
|
178 div = etree.HTML('<div></div>')[0][0] |
|
179 listNode = textParse[0].getchildren() |
|
180 for node in listNode: |
|
181 div.append(deepcopy(node)) |
|
182 return etree.tounicode(div) |
179 |
183 |
180 |
184 |
181 # HTML generation helper functions ############################################ |
185 # HTML generation helper functions ############################################ |
182 |
186 |
183 from logilab.mtconverter import html_escape |
187 from logilab.mtconverter import html_escape |