diff --git a/.gitignore b/.gitignore
index 4e6917a..e1e7a78 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,11 @@
*.*~
*.egg
*.egg-info
+*.odt
+*.txt
+.tox
+.cache
+.vscode
dist
build
-eggs
+eggs
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index f07d49e..c5c2fe9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,10 @@
+install: pip install -U tox
language: python
-python:
- - "2.6"
- - "2.7"
- - "3.3"
-install: "python setup.py develop"
-script: "python setup.py test"
+python:
+ - 2.6
+ - 2.7
+ - 3.3
+ - 3.4
+ - 3.5
+ - 3.6
+script: tox -e py${TRAVIS_PYTHON_VERSION//./}
diff --git a/README.md b/README.md
index a67c802..7bbcf96 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,13 @@
# SECRETARY
+
+
+
+
+
+
+
+
#### Take the power of Jinja2 templates to OpenOffice and LibreOffice and create reports in your web applications.
@@ -93,6 +101,10 @@ Although most of the time the automatic handling of control flow in secretary ma
* `after::cell`: Same as `after::row` but for a table cell.
> Field content is the control flow tag you insert with the Writer *input field*
+### Hyperlink Support
+LibreOffice by default escapes every URL in links, pictures or any other element supporting hyperlink functionallity. This can be a problem if you need to generate dynamic links because your template logic is URL encoded and impossible to be handled by the Jinja engine. Secretary solves this problem by reserving the `secretary` URI scheme. If you need to create dynamic links in your documents, prepend every link with the `secretary:` scheme.
+
+So for example if you have the following dynamic link: `https://mysite/products/{{ product.id }}`, prepend it with the **`secretary:`** scheme, leaving the final link as `secretary:https://mysite/products/{{ product.id }}`.
### Image Support
Secretary allows you to use placeholder images in templates that will be replaced when rendering the final document. To create a placeholder image on your template:
@@ -147,6 +159,9 @@ Pad zeroes to `value` to the left until output value's length be equal to `lengt
Secretary supports most of the jinja2 control structure/flow tags. But please avoid using the following tags since they are not supported: `block`, `extends`, `macro`, `call`, `include` and `import`.
### Version History
+* **0.2.15**: Fix bug reported in #39 escaping Line-Feed and Tab chars inside `text:` elements.
+* **0.2.14**: Implement dynamic links escaping and fix #33.
+* **0.2.13**: Fix reported bug in markdown filter outputing emply lists.
* **0.2.11**: Fix bug when unescaping `"`, `'`, `<`, `>` and '&' inside Jinja expressions.
* **0.2.10**: ---
* **0.2.9**: ---
diff --git a/secretary.py b/secretary.py
index 0922f52..41e6bdd 100644
--- a/secretary.py
+++ b/secretary.py
@@ -177,12 +177,19 @@ class Renderer(object):
self.log.debug('packing document')
zip_file = io.BytesIO()
- zipdoc = zipfile.ZipFile(zip_file, 'a')
+ mimetype = files['mimetype']
+ del files['mimetype']
+
+ zipdoc = zipfile.ZipFile(zip_file, 'a', zipfile.ZIP_DEFLATED)
+
+ # Store mimetype without without compression using a ZipInfo object
+ # for compatibility with Py2.6 which doesn't have compress_type
+ # parameter in ZipFile.writestr function
+ mime_zipinfo = zipfile.ZipInfo('mimetype')
+ zipdoc.writestr(mime_zipinfo, mimetype)
+
for fname, content in files.items():
- if sys.version_info >= (2, 7):
- zipdoc.writestr(fname, content, zipfile.ZIP_DEFLATED)
- else:
- zipdoc.writestr(fname, content)
+ zipdoc.writestr(fname, content)
self.log.debug('Document packing completed')
@@ -397,8 +404,9 @@ class Renderer(object):
def _unescape_entities(self, xml_text):
"""
- Unescape '&', '<', '"' and '>' within jinja instructions.
- The regexs rules used here are compiled in _compile_escape_expressions.
+ Unescape links and '&', '<', '"' and '>' within jinja
+ instructions. The regexs rules used here are compiled in
+ _compile_escape_expressions.
"""
for regexp, replacement in self.escape_map.items():
while True:
@@ -406,6 +414,23 @@ class Renderer(object):
if not substitutions:
break
+ return self._unescape_links(xml_text)
+
+ def _unescape_links(self, xml_text):
+ """Fix Libreoffice auto escaping of xlink:href attribute values.
+ This unescaping is only done on 'secretary' scheme URLs."""
+ import urllib
+ robj = re.compile(r'(?is)(xlink:href=\")secretary:(.*?)(\")')
+
+ def replacement(match):
+ return ''.join([match.group(1), urllib.unquote(match.group(2)),
+ match.group(3)])
+
+ while True:
+ xml_text, rep = robj.subn(replacement, xml_text)
+ if not rep:
+ break
+
return xml_text
@staticmethod
@@ -413,7 +438,11 @@ class Renderer(object):
"""
Replace line feed and/or tabs within text:span entities.
"""
+<<<<<<< HEAD
find_pattern = r'(?is)