From c581009ed1ffe67bef37898264ffd1c6e96e4400 Mon Sep 17 00:00:00 2001 From: drfho Date: Mon, 9 Dec 2024 17:06:55 +0800 Subject: [PATCH 1/2] fix standard.compareDate(): normalize tm_isdst-value in struct_time not to trigger mktime-error Ref https://github.com/zms-publishing/ZMS4/pull/6 --- Products/zms/standard.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Products/zms/standard.py b/Products/zms/standard.py index 91fdb32c1..15c0a578f 100644 --- a/Products/zms/standard.py +++ b/Products/zms/standard.py @@ -1307,7 +1307,7 @@ def format_datetime_iso(t): tz = time.timezone else: tz = 0 - # The offset of the local (non-DST) timezone, in seconds west of UTC + # The offset of the local (non-DST) timezone, in seconds west of UTC # (negative in most of Western Europe, positive in the US, zero in the # UK). # @@ -1400,6 +1400,13 @@ def getDateTime(t): t = time.mktime( t) if not isinstance(t, time.struct_time): t = time.localtime( t) + else: + if t.tm_isdst == 1: + # In struct_time normalize tm_dst-value + # (DST: Daylight Saving Time) to avoid mktime-error + t = list(t) + t[8] = -1 + t = time.localtime( time.mktime( t)) except: pass return t From 7176e03006113e96035c9beb13e6c187ff5d59d2 Mon Sep 17 00:00:00 2001 From: drfho Date: Mon, 9 Dec 2024 17:31:03 +0800 Subject: [PATCH 2/2] Added more transformation features to pydocx-export (#341) --- .../manage_export_pydocx.py | 124 +++++++++++++----- .../manage_export_pydocx/neon.docx | Bin 19736 -> 19797 bytes .../manage_export_pydocx/readme.md | 17 ++- .../manage_export_pydocx/styles.xml | 17 ++- .../ZMSGraphic/standard_json_docx.py | 24 ++-- .../ZMSTextarea/standard_json_docx.py | 14 +- 6 files changed, 141 insertions(+), 55 deletions(-) diff --git a/Products/zms/conf/metacmd_manager/manage_export_pydocx/manage_export_pydocx.py b/Products/zms/conf/metacmd_manager/manage_export_pydocx/manage_export_pydocx.py index 3b02d273b..781bb7b70 100644 --- a/Products/zms/conf/metacmd_manager/manage_export_pydocx/manage_export_pydocx.py +++ b/Products/zms/conf/metacmd_manager/manage_export_pydocx/manage_export_pydocx.py @@ -186,6 +186,7 @@ def add_hyperlink(docx_block, link_text, url): url_base = 'http://neon/' # Omit javascript links if not url.startswith('javascript:'): + url = url.replace('mailto:', '') # Fix missing domain name url = ('http' in url) and url.replace('http:///', url_base) or (url_base + (url.startswith('/') and url[1:] or url)) r_id = docx_block.part.relate_to(url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, is_external=True) @@ -222,7 +223,7 @@ def add_hyperlink(docx_block, link_text, url): # ############################################# # Clean HTML -def clean_html(html): +def clean_html(html, wrap_trailling_text=False): """ Clean comments, styles, empty tags and handle special characters: left-to-right, triangle @@ -244,6 +245,9 @@ def clean_html(html): html = html.replace(left_to_right_char,'') html = html.replace('[[', triangle_char) html = html.replace(']]', '') + if wrap_trailling_text: + # Wrap untagged text following a block element into a paragraph + html = re.sub(r'(?i)(?m)(.*?<\/div>)\s*(?=\w)(.*?)', r'\g<1>\n

\g<2>

', html) return html # ADD RUNS TO DOCX-BLOCK @@ -276,6 +280,8 @@ def add_runs(docx_block, bs_element): docx_block.add_run(u'\U0000F021', style='Icon') elif elrun.has_attr('class') and 'fa-phone' in elrun['class']: docx_block.add_run(u'\U0000F028', style='Icon') + elif elrun.has_attr('class') and 'fa-exclamation-triangle' in elrun['class']: + docx_block.add_run(u'\U0000F045', style='Icon') elif elrun.text != '': docx_block.add_run(elrun.text).italic = True elif elrun.text != '': @@ -294,6 +300,8 @@ def add_runs(docx_block, bs_element): docx_block.add_run(elrun.text).font.subscript = True elif elrun.name == 'sup': docx_block.add_run(elrun.text).font.superscript = True + elif elrun.name == 'u': + docx_block.add_run(elrun.text).underline = True elif elrun.name == 'a': if elrun.has_attr('href'): add_hyperlink(docx_block = docx_block, link_text = elrun.text, url = elrun.get('href')) @@ -355,6 +363,7 @@ def add_tagged_content_as_paragraph(docx_doc, bs_element, style_name="Standard", def add_htmlblock_to_docx(zmscontext, docx_doc, htmlblock, zmsid=None, zmsmetaid=None): # Clean HTML htmlblock = clean_html(htmlblock) + htmlblock = htmlblock.strip() heading_text = '' # Apply BeautifulSoup and iterate over elements soup = BeautifulSoup(htmlblock, 'html.parser') @@ -376,20 +385,18 @@ def add_htmlblock_to_docx(zmscontext, docx_doc, htmlblock, zmsid=None, zmsmetaid prepend_bookmark(p, zmsid) else: # ############################################# - # HTML-Elements, element.name != None - # ############################################# - - # ############################################# + # BLOCK-Elements, element.name != None + # --------------------------------------------- # HEADINGS # ############################################# - if element.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']: + if element.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7', 'h8']: heading_level = int(element.name[1]) heading_text = standard.pystr(element.text).strip() p = add_heading(docx_doc, heading_text, level=heading_level) if c==1 and zmsid: prepend_bookmark(p, zmsid) if element.text == 'Inhaltsverzeichnis': - p.style = docx_doc.styles['TOC-Header'] + p.style = doc.styles['TOC-Header'] # ############################################# # PARAGRAPH # ############################################# @@ -401,11 +408,14 @@ def add_htmlblock_to_docx(zmscontext, docx_doc, htmlblock, zmsid=None, zmsmetaid # htmlblock.__contains__('ZMSTable') or htmlblock.__contains__('img') if element.has_attr('class'): if 'caption' in element['class'] and zmsmetaid in ['ZMSGraphic', 'ZMSTable']: - p.style = docx_doc.styles['caption'] + p.style = doc.styles['caption'] else: class_name = element['class'][0] - style_name = (class_name in docx_doc.styles) and class_name or 'Normal' - p.style = docx_doc.styles[style_name] + try: + style_name = (class_name in doc.styles) and class_name or 'Normal' + except: + style_name = 'Normal' + p.style = doc.styles[style_name] add_runs(docx_block = p, bs_element = element) ## Remove empty paragraphs @@ -495,7 +505,7 @@ def add_list(docx_obj, element, level=0, c=0): # ------------------------------------------------ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): '''Convert cell html to docx''' - cl_html = clean_html(docx_cell.text) + cl_html = clean_html(docx_cell.text, wrap_trailling_text=True) cl_type = cl_html.startswith('[th:') and 'th' or 'td' cl_html = re.sub(r'\[(th|td):\d:\d\] ','',cl_html) cl = BeautifulSoup(cl_html, 'html.parser') @@ -509,7 +519,14 @@ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): try: if {'div','ol','ul','table','p'} & set([e.name for e in cl.children]): # [A] Block elements - add_htmlblock_to_docx(zmscontext, docx_cell, cl_html, zmsid=None) + try: + add_htmlblock_to_docx(zmscontext, docx_cell, cl_html, zmsid=None) + except: + p.add_run('Rendering Error Table-Cell: %s'%cl.text) + # Cleaning: remove first cell paragraph if empty + if docx_cell.paragraphs[0].text == '': + first_p = docx_cell.paragraphs[0]._element + docx_cell._tc.remove(first_p) elif set([e.name for e in cl.children])==set([None]): # [B] Just text p.text = cl.text @@ -547,7 +564,7 @@ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): img_src = zmscontext.operator_getattr(zmscontext,zmsid).attr('imghires').getHref(zmscontext.REQUEST) except: pass - img_name = img_src.split('/')[-1] + img_name = img_src.split('?')[0].split('/')[-1] if not img_src.startswith('http'): src_url0 = zmscontext.absolute_url().split('/content/')[0] src_url1 = img_src.split('/content/')[-1] @@ -583,12 +600,34 @@ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): elif element.name == 'div': if element.has_attr('class') and (('ZMSGraphic' in element['class']) or ('graphic' in element['class'])): ZMSGraphic_html = standard.pystr(''.join([str(e) for e in element.children])) + zmsid = element.has_attr('id') and element['id'] or zmsid + zmscontext = zmscontext.operator_getattr(zmscontext,zmsid) add_htmlblock_to_docx(zmscontext, docx_doc, ZMSGraphic_html, zmsid, zmsmetaid='ZMSGraphic') elif element.has_attr('class') and ('ZMSTextarea' in element['class']): ZMSTextarea_html = standard.pystr(''.join([str(e) for e in element.children])) + zmsid = element.has_attr('id') and element['id'] or zmsid + zmscontext = zmscontext.operator_getattr(zmscontext,zmsid) add_htmlblock_to_docx(zmscontext, docx_doc, ZMSTextarea_html, zmsid, zmsmetaid='ZMSTextarea') elif element.has_attr('class') and 'handlungsaufforderung' in element['class']: - add_tagged_content_as_paragraph(docx_doc, element, 'Handlungsaufforderung', c, zmsid) + if len([e.name for e in element.children if e.name in ['ul','ol']])>0: + add_tagged_content_as_paragraph(docx_doc, element, 'Handlungsaufforderung', c, zmsid) + child_tag = [e.name for e in element.children if e.name][0] + # COPY add_list + def add_list(docx_obj, element, level=0, c=0): + for i, li in enumerate(element.find_all('li', recursive=False)): + if docx_obj.paragraphs and docx_obj.paragraphs[-1].text == '': + p = docx_obj.paragraphs[-1] + else: + p = docx_obj.add_paragraph() + p = set_block_as_listitem(p, list_type=element.name, level=level, i=i) + add_runs(docx_block = p, bs_element = li) + if c==1 and zmsid: + prepend_bookmark(p, zmsid) + for ul in li.find_all(['ul','ol'], recursive=False): + add_list(docx_doc, ul, level+1) + add_list(docx_doc, element.find(child_tag), level=1, c=c) + else: + add_tagged_content_as_paragraph(docx_doc, element, 'Handlungsaufforderung', c, zmsid) elif element.has_attr('class') and 'grundsatz' in element['class']: add_tagged_content_as_paragraph(docx_doc, element, 'Grundsatz', c, zmsid) elif element.has_attr('style') and 'background: rgb(238, 238, 238)' in element['style'] \ @@ -601,14 +640,14 @@ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): add_runs(docx_block = p, bs_element = element) else: child_tags = [e.name for e in element.children if e.name] - if {'em','strong','i', 'span'} & set(child_tags): + if {'em','strong','i','span','u'} & set(child_tags): p = docx_doc.add_paragraph() if c==1 and zmsid: prepend_bookmark(p, zmsid) if len(element.contents) == 1: if element.has_attr('class'): - style_name = (class_name in docx_doc.styles) and class_name or 'Normal' - p.style = docx_doc.styles[style_name] + style_name = (class_name in doc.styles) and class_name or 'Normal' + p.style = doc.styles[style_name] p.add_run(element.text) elif len(element.contents) > 1: for e in element.contents: @@ -621,8 +660,15 @@ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): # p.add_run('Routing: ') p.add_run(u'\U0000F028', style='Icon') p.add_run(' ') + elif 'fa-exclamation-triangle' in class_name: + # p.add_run('Kommentar: ') + p.add_run(u'\U0000F045', style='Icon') + p.add_run(' ') if list(e.children)!=[]: - add_runs(docx_block = p, bs_element = e) + if [ch.name for ch in e.children if ch.name in ['p', 'ol', 'ul', 'div']]: + add_htmlblock_to_docx(zmscontext, docx_doc, standard.pystr(e), zmsid) + else: + add_runs(docx_block = p, bs_element = e) else: p.add_run(standard.pystr(e.text)) elif e.name: @@ -678,8 +724,9 @@ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): for input_field in element.find_all('input', recursive=True): input_field_count += 1 p.add_run('%s. : %s\n'%(input_field_count, input_field.get('name',''))) + # ############################################# - # OTHERS + # OTHER ELEMENTS # ############################################# elif element.name == 'hr': # Omit horizontal rule @@ -687,6 +734,9 @@ def convert_cell_html_to_docx(zmscontext, docx_cell, text_style='Normal'): elif element.name == 'script': # Omit javascript pass + elif element.name == 'style': + # Omit style + pass else: try: if element.has_text: @@ -705,7 +755,7 @@ def add_breadcrumbs_as_runs(zmscontext, p): c = 0 for obj in breadcrumbs: c += 1 - link_text = obj.meta_id == 'ZMS' and standard.pystr(obj.attr('title')) or standard.pystr(obj.attr('titlealt')) + link_text = obj.meta_id == 'ZMS' and standard.pystr(obj.attr('title')) or standard.pystr(obj.getTitlealt(zmscontext.REQUEST)) add_hyperlink(docx_block = p, link_text = link_text, url = obj.getHref2IndexHtml(zmscontext.REQUEST)) if c < len(breadcrumbs): p.add_run(' > ') @@ -755,7 +805,9 @@ def apply_standard_json_docx(self): zmscontext = self request = zmscontext.REQUEST + # For debugging use preview content # request.set('preview', 'preview') + # ################################# is_page = zmscontext.isPage() id = zmscontext.id @@ -794,7 +846,7 @@ def apply_standard_json_docx(self): pageelements = [ \ e for e in zmscontext.getChildNodes(request) \ if ( ( e.getType() in [ 'ZMSObject', 'ZMSRecordSet'] ) \ - and not e.meta_id in [ 'LgChangeHistory','ZMSTeaserContainer','LgELearningBanner'] \ + and not e.meta_id in [ 'LgChangeHistory','ZMSTeaserContainer'] \ and not e.isPage() ) \ or e.meta_id in [ 'ZMSLinkElement' ] ] @@ -832,7 +884,7 @@ def apply_standard_json_docx(self): 'parent_id':parent_id, 'parent_meta_id':parent_meta_id, 'docx_format':'image', - 'imgwidth': imgwidth, + 'imgwidth': imgwidth, 'imgheight':imgheight, 'content':img_url }, @@ -938,7 +990,7 @@ def apply_standard_json_docx(self): }] # Give some customizing hints for standard_html - if pageelement.meta_id in ['LgRegel','LgBedingung','LgELearningBanner','ZMSNote']: + if pageelement.meta_id in ['LgRegel','LgBedingung','LgELearningBanner','ZMSNote','ZMSTestarea']: standard.writeStdout(None, 'IMPORTANT NOTE: %s.standard_html needs to be customized!'%(pageelement.meta_id)) # %<---- CUSTOMIZE LIKE THIS --------------------- # zmi python:request['URL'].find('/manage')>0 and not request['URL'].find('pydocx')>0; @@ -1057,6 +1109,7 @@ def add_heading(self, text, level=1): # binary data of the DOCX file. def manage_export_pydocx(self, save_file=True, file_name=None): request = self.REQUEST + request.set('lang', self.getPrimaryLanguage()) docx_creator = request.AUTHENTICATED_USER.getUserName() # PAGE_COUNTER: Counter for recursive export @@ -1207,22 +1260,21 @@ def manage_export_pydocx(self, save_file=True, file_name=None): # ############################################# # [4] CAPTION TEXT-BLOCK elif v and block['docx_format']=='Caption': - if re.match(r'^\[Abb. e\d+\] .*', v): - capt_list = re.split(r'^\[Abb. e\d+\] ', v) - if len(capt_list) > 1 and len(capt_list[1]) > 0: - p = doc.add_paragraph(style='Caption') - prepend_bookmark(p, block['id']) - p.add_run('Abb. %s: '%block['id']).font.italic = False - p.add_run(capt_list[1]) - elif re.match(r'^\[Abb. e\d+\] ', v): - # Omit caption with empty text - pass + p = doc.add_paragraph(style='Caption') + if re.match(r'^\[Abb\. e\d+\] .*', v): + re_list = re.split(r'^(\[Abb. e\d+\]) (.*)',v) + v1 = re_list[1] + v2 = BeautifulSoup(re_list[2], 'html.parser').get_text() + p.add_run(v1).font.italic = False + p.add_run(' ') + p.add_run(v2) else: - p = doc.add_paragraph(style='Caption') - prepend_bookmark(p, block['id']) + p.add_run(v) + prepend_bookmark(p, block['id']) + # ############################################# # [5] TEXT-BLOCK with given block format (style) - elif v and block['docx_format'] in [e.name for e in doc.styles]: + elif v and ( block['docx_format'] in [e.name for e in doc.styles] or block['docx_format'] in [e.name.replace(' ','') for e in doc.styles] ): p = doc.add_paragraph(v, style=block['docx_format']) prepend_bookmark(p, block['id']) elif v: diff --git a/Products/zms/conf/metacmd_manager/manage_export_pydocx/neon.docx b/Products/zms/conf/metacmd_manager/manage_export_pydocx/neon.docx index 57e177f41f262ce8bd16e90b95adc5c1320d91bb..0d3d8a0915094d697c1d1ec5108af63659913221 100644 GIT binary patch delta 2743 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 delta 2661 zcmV-r3YzuRngN)a0kBXlf2MtXSr|0cp3MmW0CPkD01p5F0C#V4WG{1cd2D5KE_iKh z)mz!F(=ZTy28n-&@?MgrX=xFQ;L-wOrz{e0ZsOh=(j?dk+t2XApYUUh}(?K!h~?B2Tj?dT|9FlEGZZ>!Vmx~gE;@@(Q>-d5kf*-VzIf5HOf+Q{)-d|UmF znR@rmwX3(j-ekdd2Qvj2xa{W9x~(39z`v@h z9<_byS(q`{`q7D4f5Li+o98q&E4+@xq8{`1!FAYGysn5FaG2`Rr=wHgG4IF2$n!W_ zHy>ZR9z{C`z<~8Az)!scBLIl)Sr70Yg-*bD5AUKcY23wok}m!^Zfra^V9M8AJ|QI8_v@i&QiRP&j=ci6woH7y94x+v11)W3|e~Q}W1sGl00EULCL)=f5nMTLV zZ9qNuvNCPfF>QVH4~P*~nP_%Qd=-KiDzoOQCShsH8}80KNtLIB1%m39R&*iI2fay5 zhB?7^pNstfwrBx7kvE9!Q@Dbd@G*Fbdpm}LACqkqHW_)g z^lbOZe~cW&EOlHNeZgXuC8hdjn3V9uFk!KJs5VzETd6+1ODiAM4o zxI=)(3pXCk#Hpoo@wcEn+9pv$PNM#OTQtNff4m^@jtL8%mx<88esG40kSuI=C1RW7 zQ4sv}#)IXJEbI%OEm+JJ85U71!@@B2IxJFV7N|bRAw%(rgEixeBmmReq1 zGCt1@eZtf&%Cek9nIcuH=1_B>&+?uj>a)W%b`R4!CCZ}k85LH z8=g#8r<)(FgWCq+Vq^e~r96PMF#sgFe~%Ze7Fd0JVCSvC&d(3*ybIVHV*{(p18a5z zn~#Z^Q?3+{&Jg$(tp*I*+?dc>wG zaH~~kWO1UairT?}POCe1KaUkZ#oORXph>nl@eb{QV?!?M?Ut6Q@pWF^vL5 z$|n5%6X<$X!(s*RU%o7?v1xTlA->0gPJ%U$V}N#yH_}$Z2f}XbJ$#Qre+su)3Q((* zlw2NylyH?tUlU)@l4&%Y(}9Uhb+k2J-i!X~y@NTHfi~-!xH0)h&@5v#HzhENVUetj z{R^SLEH?m%;kvF&Gm5GOP1o8JHtc9Tt~b3=;m zhOv~PGiJIeMYmk)GITR@F0~I+pBWO)COvxQDt^4x|H@1<^Q>l_O^V%|oa;CA%_g5{ z_O<}oJU!LlX3Lm}@ge84lEp~d$_a^oRs0eOe=P8ps$K@)_~kxvfAwD#zZmJ`ndB=) zoO4gdm4I<_B_=+?C}$V5tnz0d$$OBl0vIL=MAh4*&|M&-8%#V7*?fH)`QD zdOp!VwrX=GF)&2d0|eSbZmHg;F(`9Mg*S!oAqv^>&lE$vXe@Rm?yK0Fxv;Ev=p}p$ z77sA9C}~P#lkvZof6D&FM;z%z{rKs?JxY*Md|>))t2`sFb?_2|6SBPZ%B0R`P=e?Q z*<=e3n;IVYWaDxuR#UJ-24+g$p36wQM#6vn94O?|d>SlK$jLChW|4lAPAeN%e-F>L&%J>BsKGfKJO$;z z^SdElJP%d1L1}$ZP%|v|8VKdziDbAslpivGe97EwARu5sfUOgKqdz?4g zRMicSqLnrur*PzMEMmeo(Hl2X(MK)0(44xf>@w3>&IZ29Z;Gjhi4BgP1(yT`jZPR@;pvS#snA1z#_-w^uY2U`ct*jyxYjh*jOqXovCdU zpgN_^Mti8O%z=Wr3>dh1z)u z%j;lvODnB3?dpkKid77fOQEFDrnAaJO6&%eEg~)tXa%PGQ3A;%qDVfU*GtY*E{4c* zkUg4|c}T_&Sr)`)py`jsVDj#CCbzUaPF?z!1hzQkAG3Wo*%J<|d zM3ZDoF9z(0Q%Y?@lbK6A0YH=1OF{uzlNn4w0e6#IOi2PDK9hMqACr1a5R=tR8UYuR T@Jv7f9+NRm9tKH900000Mz0+L diff --git a/Products/zms/conf/metacmd_manager/manage_export_pydocx/readme.md b/Products/zms/conf/metacmd_manager/manage_export_pydocx/readme.md index 255a4bdcd..85ca1862b 100644 --- a/Products/zms/conf/metacmd_manager/manage_export_pydocx/readme.md +++ b/Products/zms/conf/metacmd_manager/manage_export_pydocx/readme.md @@ -17,6 +17,19 @@ pip install python-docx ## Configuration and Customization -Ensure that the script is configured correctly with the necessary parameters for your specific use case (especially the global variable `docx_tmpl` as filesystem path to the DOCX file that is used as a template). You may need to modify the script to fit your data source and desired output format. -Some (complex) ZMS content objects may need another template `standard_json_docx` (Python script) to generate a normalized JSON representation of the object's content. The standard content model contains some examples of the script. For further details, please refer to the docstring of +Ensure that the script is configured correctly with the necessary parameters for your specific use case, especially the global variable `docx_tmpl` as filesystem path to the DOCX file that is used as a template: + +```py +# Set local path for docx-template +docx_tmpl = open("/home/zope/src/zms-publishing/ZMS5/Products/zms/conf/metacmd_manager/manage_export_pydocx/neon.docx", "rb") +``` + +You may prefer to export not the committed but the working content, so set the REQUEST-variable: + +```py +# For debugging use preview content +request.set('preview', 'preview') +``` + +Furthermore You may need to modify the script to fit your data source and desired output format. Some (complex) ZMS content objects may need another template `standard_json_docx` (Python script) to generate a normalized JSON representation of the object's content. The standard content model contains some examples of the script. For further details, please refer to the docstring of `manage_export_pydocx.apply_standard_json_docx()`. diff --git a/Products/zms/conf/metacmd_manager/manage_export_pydocx/styles.xml b/Products/zms/conf/metacmd_manager/manage_export_pydocx/styles.xml index b83c53633..981f0c4e9 100644 --- a/Products/zms/conf/metacmd_manager/manage_export_pydocx/styles.xml +++ b/Products/zms/conf/metacmd_manager/manage_export_pydocx/styles.xml @@ -108,6 +108,8 @@ + + @@ -126,6 +128,8 @@ + + @@ -145,6 +149,8 @@ + + @@ -166,11 +172,15 @@ + + - + + + @@ -190,9 +200,10 @@ - + + - + diff --git a/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSGraphic/standard_json_docx.py b/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSGraphic/standard_json_docx.py index 823ba0e4e..a3b44bdcb 100644 --- a/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSGraphic/standard_json_docx.py +++ b/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSGraphic/standard_json_docx.py @@ -8,6 +8,12 @@ ##title=JSON ## # --// standard_json_docx //-- +# This Python script is used to generate a normalized JSON representation +# of the object's content, which is then used by ZMS-action manage_export_pydocx +# for exporting its content to a Word file. +# For further details, please refer to the docstring of +# manage_export_pydocx.apply_standard_json_docx(). +# from Products.zms import standard request = zmscontext.REQUEST @@ -17,27 +23,29 @@ parent_meta_id = zmscontext.getParentNode().meta_id text = zmscontext.attr('text') img = zmscontext.attr('imghires') or zmscontext.attr('img') -img_url = img.getHref(request) +img_url = '%s/%s'%(zmscontext.absolute_url(),img.getHref(request).split('/')[-1]) imgwidth = img and int(img.getWidth()) or 0; imgheight = img and int(img.getHeight()) or 0; blocks = [ { - 'id':id, + 'id':'%s_img'%(id), 'meta_id':meta_id, 'parent_id':parent_id, 'parent_meta_id':parent_meta_id, - 'docx_format':'Caption', - 'content':text + 'docx_format':'image', + 'imgwidth':imgwidth, + 'imgheight':imgheight, + 'content':img_url }, { - 'id':'%s_1'%(id), + 'id':id, 'meta_id':meta_id, 'parent_id':parent_id, 'parent_meta_id':parent_meta_id, - 'docx_format':'html', - 'content':''%(img_url, imgwidth, imgheight) - } + 'docx_format':'Caption', + 'content':'[Abb. %s] %s'%(id, text) + }, ] return blocks diff --git a/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSTextarea/standard_json_docx.py b/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSTextarea/standard_json_docx.py index 2928fddae..b9a114f8d 100644 --- a/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSTextarea/standard_json_docx.py +++ b/Products/zms/conf/metaobj_manager/com.zms.foundation/ZMSTextarea/standard_json_docx.py @@ -28,12 +28,14 @@ "body" : "Normal", "blockquote" : "Quote", "caption" : "Caption", - "headline_1" : "Heading1", - "headline_2" : "Heading2", - "headline_3" : "Heading3", - "headline_4" : "Heading4", - "headline_5" : "Heading5", - "headline_6" : "Heading6", + "headline_1" : "Heading 1", + "headline_2" : "Heading 2", + "headline_3" : "Heading 3", + "headline_4" : "Heading 4", + "headline_5" : "Heading 5", + "headline_6" : "Heading 6", + "headline_7" : "Heading 7", + "headline_8" : "Heading 8", "ordered_list" : "ListBullet", "unordered_list" : "ListBullet", "plain_html": "html",