@@ -274,20 +274,139 @@ def get_heading_tag(self, paragraph):
274274 return HtmlTag (tag , id = paragraph .bookmark_name )
275275 return HtmlTag (tag )
276276
277+ def export_run (self , run ):
278+ results = super (PyDocXHTMLExporter , self ).export_run (run )
279+
280+ for result in self .export_borders (run , results , tag_name = 'span' ):
281+ yield result
282+
277283 def export_paragraph (self , paragraph ):
278284 results = super (PyDocXHTMLExporter , self ).export_paragraph (paragraph )
279285
280286 results = is_not_empty_and_not_only_whitespace (results )
281- if results is None :
287+
288+ # TODO@botzill In PR#234 we render empty paragraphs properly so
289+ # we don't need this check anymore. Adding for now and to be removed when merging
290+ if results is None and not paragraph .has_border_properties :
282291 return
283292
284293 tag = self .get_paragraph_tag (paragraph )
285294 if tag :
286295 results = tag .apply (results )
287296
297+ for tag in self .export_borders (paragraph , results , tag_name = 'div' ):
298+ yield tag
299+
300+ def export_close_paragraph_border (self ):
301+ if self .current_border_item .get ('Paragraph' ):
302+ yield HtmlTag ('div' , closed = True )
303+ self .current_border_item ['Paragraph' ] = None
304+
305+ def export_borders (self , item , results , tag_name = 'div' ):
306+ if self .first_pass :
307+ for result in results :
308+ yield result
309+ return
310+
311+ # For now we have here Paragraph and Run
312+ item_name = item .__class__ .__name__
313+ item_is_run = isinstance (item , wordprocessing .Run )
314+ item_is_paragraph = isinstance (item , wordprocessing .Paragraph )
315+
316+ prev_borders_properties = None
317+ border_properties = None
318+ current_border_item = self .current_border_item .get (item_name )
319+ if current_border_item :
320+ prev_borders_properties = current_border_item .\
321+ effective_properties .border_properties
322+
323+ last_item = False
324+ close_border = True
325+
326+ def current_item_is_last_child (children , child_type ):
327+ for p_child in reversed (children ):
328+ if isinstance (p_child , child_type ):
329+ return p_child == item
330+ return False
331+
332+ def is_last_item ():
333+ if item_is_paragraph :
334+ if isinstance (item .parent , wordprocessing .TableCell ):
335+ return current_item_is_last_child (
336+ item .parent .children , wordprocessing .Paragraph )
337+ elif item == self .last_paragraph :
338+ return True
339+ elif item_is_run :
340+ # Check if current item is the last Run item from paragraph children
341+ return current_item_is_last_child (item .parent .children , wordprocessing .Run )
342+
343+ return False
344+
345+ if item .effective_properties :
346+ border_properties = item .effective_properties .border_properties
347+ if border_properties :
348+ last_item = is_last_item ()
349+ close_border = False
350+ run_has_different_parent = False
351+
352+ # If run is from different paragraph then we may need to draw separate border
353+ # even if border properties are the same
354+ if item_is_run and current_border_item :
355+ if current_border_item .parent != item .parent :
356+ run_has_different_parent = True
357+
358+ if border_properties != prev_borders_properties or run_has_different_parent :
359+ if prev_borders_properties is not None :
360+ # We have a previous border tag opened, so need to close it
361+ yield HtmlTag (tag_name , closed = True )
362+
363+ # Open a new tag for the new border and include all the properties
364+ border_attrs = self .get_borders_property (border_properties )
365+ yield HtmlTag (tag_name , closed = False , ** border_attrs )
366+
367+ self .current_border_item [item_name ] = item
368+ else :
369+ if prev_borders_properties is not None and \
370+ getattr (border_properties , 'between' , None ):
371+ # Render border between items
372+ border_attrs = self .get_borders_property (
373+ border_properties , only_between = True )
374+
375+ yield HtmlTag (tag_name , ** border_attrs )
376+ yield HtmlTag (tag_name , closed = True )
377+
378+ if close_border and prev_borders_properties is not None :
379+ # At this stage we need to make sure that if there is an previously open tag
380+ # about border we need to close it
381+ yield HtmlTag (tag_name , closed = True )
382+ self .current_border_item [item_name ] = None
383+
384+ # All the inner items inside border tag are issued here
288385 for result in results :
289386 yield result
290387
388+ if border_properties and last_item :
389+ # If the item with border is the last one we need to make sure that we close the
390+ # tag
391+ yield HtmlTag (tag_name , closed = True )
392+ self .current_border_item [item_name ] = None
393+
394+ def get_borders_property (self , border_properties , only_between = False ):
395+ attrs = {}
396+ style = {}
397+
398+ if only_between :
399+ style .update (border_properties .get_between_border_style ())
400+ else :
401+ style .update (border_properties .get_padding_style ())
402+ style .update (border_properties .get_border_style ())
403+ style .update (border_properties .get_shadow_style ())
404+
405+ if style :
406+ attrs ['style' ] = convert_dictionary_to_style_fragment (style )
407+
408+ return attrs
409+
291410 def export_paragraph_property_justification (self , paragraph , results ):
292411 # TODO these classes could be applied on the paragraph, and not as
293412 # inline spans
@@ -633,8 +752,17 @@ def export_table(self, table):
633752 table_cell_spans = table .calculate_table_cell_spans ()
634753 self .table_cell_rowspan_tracking [table ] = table_cell_spans
635754 results = super (PyDocXHTMLExporter , self ).export_table (table )
755+
756+ # Before starting new table new need to make sure that if there is any paragraph
757+ # with border opened before, we need to close it here.
758+ for result in self .export_close_paragraph_border ():
759+ yield result
760+
636761 tag = self .get_table_tag (table )
637- return tag .apply (results )
762+ results = tag .apply (results )
763+
764+ for result in results :
765+ yield result
638766
639767 def export_table_row (self , table_row ):
640768 results = super (PyDocXHTMLExporter , self ).export_table_row (table_row )
0 commit comments