44
55class Html2Doc
66 def style_list ( elem , level , liststyle , listnumber )
7- return unless liststyle
8-
7+ liststyle or return
98 if elem [ "style" ]
109 elem [ "style" ] += ";"
1110 else
@@ -30,16 +29,37 @@ def list_add1(elem, liststyles, listtype, level)
3029
3130 def list_add ( xpath , liststyles , listtype , level )
3231 xpath . each do |l |
33- level == 1 and l [ "seen" ] = true and @listnumber += 1
32+ level == 1 && l [ "seen" ] = true and @listnumber += 1
3433 l [ "id" ] ||= UUIDTools ::UUID . random_create
34+ liststyle = derive_liststyle ( l , liststyles [ listtype ] , level )
3535 ( l . xpath ( ".//li" ) - l . xpath ( ".//ol//li | .//ul//li" ) ) . each do |li |
36- style_list ( li , level , liststyles [ listtype ] , @listnumber )
36+ style_list ( li , level , liststyle , @listnumber )
3737 list_add1 ( li , liststyles , listtype , level )
3838 end
3939 list_add_tail ( l , liststyles , listtype , level )
4040 end
4141 end
4242
43+ def derive_liststyle ( list , liststyle , level )
44+ list [ "start" ] && list [ "start" ] != "1" or return liststyle
45+ @liststyledefsidx += 1
46+ ret = "l#{ @liststyledefsidx } "
47+ @newliststyledefs += newliststyle ( list [ "start" ] , liststyle , ret , level )
48+ ret
49+ end
50+
51+ def newliststyle ( start , liststyle , newstylename , level )
52+ s = @liststyledefs [ liststyle ]
53+ . gsub ( /@list\s +#{ liststyle } / , "@list #{ newstylename } " )
54+ . sub ( /@list\s +#{ newstylename } \s +\{ [^}]*\} /m , <<~LISTSTYLE )
55+ @list #{ newstylename } \n {mso-list-id:#{ rand ( 100_000_000 ..999_999_999 ) } ;
56+ mso-list-template-ids:#{ rand ( 100_000_000 ..999_999_999 ) } ;}
57+ LISTSTYLE
58+ . sub ( /@list\s +#{ newstylename } :level#{ level } \s +\{ /m ,
59+ "\\ 0mso-level-start-at:#{ start } ;\n " )
60+ "#{ s } \n "
61+ end
62+
4363 def list_add_tail ( list , liststyles , listtype , level )
4464 list . xpath ( ".//ul[not(ancestor::li/ancestor::*/@id = '#{ list [ 'id' ] } ')] | " \
4565 ".//ol[not(ancestor::li/ancestor::*/@id = '#{ list [ 'id' ] } ')]" )
@@ -49,16 +69,15 @@ def list_add_tail(list, liststyles, listtype, level)
4969 end
5070
5171 def list2para ( list )
52- return if list . xpath ( "./li" ) . empty?
53-
72+ list . xpath ( "./li" ) . empty? and return
5473 list2para_position ( list )
5574 list . xpath ( "./li" ) . each do |l |
5675 l . name = "p"
5776 l [ "class" ] ||= "MsoListParagraphCxSpMiddle"
58- next unless l . first_element_child &.name == "p"
59-
77+ l . first_element_child &.name == "p" or next
6078 l [ "style" ] ||= ""
61- l [ "style" ] += ( l . first_element_child [ "style" ] &.sub ( /mso-list[^;]+;/ , "" ) || "" )
79+ l [ "style" ] += l . first_element_child [ "style" ]
80+ &.sub ( /mso-list[^;]+;/ , "" ) || ""
6281 l . first_element_child . replace ( l . first_element_child . children )
6382 end
6483 list . replace ( list . children )
@@ -100,12 +119,82 @@ def lists_unstyled(docxml, liststyles)
100119 end
101120
102121 def lists ( docxml , liststyles )
103- return if liststyles . nil?
104-
105- @listnumber = 0
122+ liststyles . nil? and return
123+ parse_stylesheet_line_styles
106124 liststyles . each_key { |k | lists1 ( docxml , liststyles , k ) }
107125 lists_unstyled ( docxml , liststyles )
108126 liststyles . has_key? ( :ul ) and docxml . xpath ( "//ul" ) . each { |u | list2para ( u ) }
109127 liststyles . has_key? ( :ol ) and docxml . xpath ( "//ol" ) . each { |u | list2para ( u ) }
110128 end
129+
130+ def parse_stylesheet_line_styles
131+ @listnumber = 0
132+ result = process_stylesheet_lines ( @stylesheet . split ( "\n " ) )
133+ @liststyledefs = clean_result_content ( result )
134+ @newliststyledefs = ""
135+ @liststyledefsidx = @liststyledefs . keys . map do |k |
136+ k . sub ( /^.*(\d +)$/ , "\\ 1" ) . to_i
137+ end . max
138+ end
139+
140+ private
141+
142+ def extract_list_name ( line )
143+ match = line . match ( /^\s *@list\s +([^:\s ]+)(?::.*)?/ )
144+ match ? match [ 1 ] : nil
145+ end
146+
147+ def list_declaration? ( line )
148+ !extract_list_name ( line ) . nil?
149+ end
150+
151+ def save_current_list ( result , current_base , current_content )
152+ current_base . nil? || current_content . empty? and return result
153+ if result [ current_base ]
154+ result [ current_base ] += current_content
155+ else
156+ result [ current_base ] = current_content
157+ end
158+ result
159+ end
160+
161+ def process_stylesheet_lines ( lines )
162+ result = { }
163+ current_base = nil
164+ current_content = ""
165+ parsing_active = false
166+
167+ lines . each do |line |
168+ if list_declaration? ( line )
169+ base_name = extract_list_name ( line )
170+ if current_base == base_name
171+ current_content += "#{ line } \n "
172+ else
173+ # save accumulated list style definition, new list style
174+ save_current_list ( result , current_base , current_content )
175+ current_base = base_name
176+ current_content = "#{ line } \n "
177+ end
178+ parsing_active = true
179+
180+ elsif parsing_active && line . include? ( "}" )
181+ # End of current block - add this line and stop parsing
182+ current_content += "#{ line } \n "
183+ parsing_active = false
184+
185+ elsif parsing_active
186+ # Continue adding content while parsing is active
187+ current_content += "#{ line } \n "
188+ end
189+ # If parsing_active is false and no @list declaration, skip the line
190+ end
191+ # Save the last list if we were still parsing
192+ save_current_list ( result , current_base , current_content )
193+ result
194+ end
195+
196+ def clean_result_content ( result )
197+ result . each { |k , v | result [ k ] = v . rstrip }
198+ result
199+ end
111200end
0 commit comments