Editorial Workflows

Pandoc

public workflow

Install Workflow...

This workflow contains at least one Python script. Only use it if you trust the person who shared this with you, and if you know exactly what it does.

I understand, install the workflow!

This is a workflow for Editorial, a Markdown and plain text editor for iOS. To download it, you need to view this page on a device that has the app installed.

Description: Sends the Markdown, HTML, or LaTeX text that is currently in the editor to the web service Docverter for conversion into Markdown, HTML, LaTeX, PDF, EPUB, or even DOCX. Allows users to turn on several options for Docverter, which uses Pandoc for text conversion.

For Markdown, HTML, and LaTeX output, users can choose whether to replace the editor text with the converted text or to place the converted text onto the clipboard.

For file output, the workflow will prompt the user to open the returned PDF, EPUB, or DOCX file in an appropriate app.

By configuring the red actions in the workflow, users can create custom CSS styles for PDF output can be defined in workflow action and specify a folder where the workflow can look for files referenced by Docverter arguments that require files, such as "template."

Requires Editorial 1.1.1.

Please report bugs on Twitter.

Comments: Comment Feed (RSS)

dave — 15 Sep 2017
Any chance you'll add support for jpg in the document?
...dave

+ Add Comment

Workflow Preview
Customize CSS for PDF Output ?
Variable Name
Css
Value
body {margin: 1em; } p {line-height: 1.2em; text-align: justify;} h1, h2, h3, h4 {font-weight: normal;} sup {line-height: 0;} hr {border: 1px #eee solid; margin-top: 2em; margin-bottom: 2em; width: 70%;} pre {white-space: pre-wrap; word-wrap: break-word;} @page {margin: 1in; @bottom-center{content: counter(page)};}
Get Current File Name ?
Include Folder
OFF
Include Extension
OFF
Set Variable ?
Variable Name
Filename
Value
Input
Pick Folder for Other Files ?
Run Python Script ?
Source Code
#coding: utf-8

## For more information, see:
## http://www.docverter.com/api.html
## http://wcm1.web.rice.edu/pandoc-on-ios.html

import clipboard
import console
import editor
import httplib
import json
import mimetypes
import os
import shutil
import ui
import urllib
import webbrowser
import workflow

########################
#                      #
#  GLOBAL VARIABLES    #
#                      #
########################

view = None

# Variables defined by red actions in workflow
filename = urllib.quote_plus(workflow.get_variable('Filename'), '/')
folder_path = workflow.get_variable('FolderPath')

# Variables governed by Docverter API
md_only = ['atx_headers', 'reference_links']
non_file_only = ['button1', 'button2']
args_with_files = ['template', 'include_in_header', 'include_before_body', 'include_after_body', 'reference_docx', 'epub_stylesheet', 'epub_cover_image', 'epub_metadata', 'epub_embed_font']

def clear_vars():
    global formats, fields, files, text
    formats = {}
    fields = []
    files = []
    scrollview['textfield1'].text = ''
    text = ''


########################
#                      #
#  FORM-DATA HELPERS   #
#                      #
########################

## Updated to reflect changes to httplib in Python 2.0.
## {{{ http://code.activestate.com/recipes/146306/ (r1)
 
def post_multipart(fields, files):
    """
    Post fields and files to Docverter as multipart/form-data.
    Return the server's response page or error alert
    """
    content_type, body = encode_multipart_formdata(fields, files)
    bodystr = body.encode('utf-8', 'replace')
    h = httplib.HTTPConnection('c.docverter.com')
    h.putrequest('POST', '/convert')
    h.putheader('content-type', content_type)
    h.putheader('content-length', str(len(bodystr)))
    h.endheaders()
    h.send(bodystr)
    r = h.getresponse()
    output = r.read()
    if r.status == 200: 	
    	return output
    else:
    	try:
    		error = json.loads(output)['error']
    	except Exception as e:
    		error = e
    	message = '%s %s: %s' % (r.status, r.reason, error)
    	console.hud_alert(message, 'error', 4)
    	workflow.stop()
 
def encode_multipart_formdata(fields, files):
    """
    fields = (name, value) elements for regular form fields.
    files = (name, filename, value) elements for uploaded file data
    Return (content_type, body) ready for httplib.HTTP instance
    """
    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, filename, value) in files:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % get_content_type(filename))
        L.append('')
        L.append(value)
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body
 
def get_content_type(filename):
    return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
## end of http://code.activestate.com/recipes/146306/ }}}




########################
#                      #
#  CUSTOM UI HANDLERS  #
#                      #
########################

# switch
def switch_action(sender):
    param = (sender.name, 'true')
    if sender.value:
        fields.append(param)
    elif param in fields and not sender.value:
        fields.remove(param)

# switch
def to_pdf_epub_docx(sender):
    global formats
    if sender.value:
        scrollview['to'].segments = ('pdf', 'epub', 'docx')
        scrollview['button3'].enabled = True
        scrollview['table_of_contents'].enabled = True
        for opt in md_only + non_file_only:
            scrollview[opt].enabled = False
    else:
        scrollview['to'].segments = ('markdown', 'html', 'latex')
        scrollview['button3'].enabled = False 
        for opt in non_file_only:
            scrollview[opt].enabled = True
    scrollview['to'].selected_index = 0
    set_to(scrollview['to'])

# segmented control
def set_from(sender):
    global formats
    formats['from'] = sender.segments[sender.selected_index]
    
# segmented control
def set_to(sender):
    global formats
    formats['to'] = sender.segments[sender.selected_index]
    if formats['to'] == 'markdown':
        scrollview['table_of_contents'].enabled = False
        for opt in md_only:
            scrollview[opt].enabled = True
    else:
        scrollview['table_of_contents'].enabled = True
        for opt in md_only:
            scrollview[opt].enabled = False

# button1
def out_to_editor(sender):
    input_to_files()
    args_to_fields(scrollview['textfield1'])
    request = post_multipart(formats.items() + fields, files)
    editor.replace_text(0, len(text), request)
    view.close()

# button2
def out_to_clipboard(sender):
    input_to_files()
    args_to_fields(scrollview['textfield1'])
    request = post_multipart(formats.items() + fields, files)
    clipboard.set(request)
    console.hud_alert('Converted text on clipboard!', 'success')
    view.close()

# button3
def out_to_file(sender):
    global files, fields
    input_to_files()
    args_to_fields(scrollview['textfield1'])
    if workflow.get_variable('Css'):
        c = open('custom.css', 'w').write(workflow.get_variable('Css'))
        files.append(('other_files[]', 'custom.css', open('custom.css', 'r').read()))
        fields.append(('css', 'custom.css'))
    request = post_multipart(formats.items() + fields, files)
    ext = scrollview['to'].segments[scrollview['to'].selected_index]
    o = open('docverter/' + filename + '.' + ext, 'w').write(request)
    output_path = os.path.abspath('docverter/' + filename + '.' + ext)
    open_file(output_path)
	
	


########################
#                      #
#  MAIN EXECUTE BLOCK  #
#                      #
########################

def input_to_files():
    global files, text
    text = editor.get_text()
    fw = open('docverterin.txt', 'w')
    fw.write(text)
    fw.close()
    files.append(('input_files[]', 'docverterin.txt', open('docverterin.txt', 'r').read()))
	
def args_to_fields(sender):
    global fields, files
    args = sender.text
    args_list = [i.rstrip() for i in args.split('--') if i is not '']
    for arg in args_list:
        param = tuple(arg.split('='))
        if len(param) == 1:
            fields.append(param + tuple(['true']))
        elif param[0] in args_with_files:
        	  fp = os.path.join(folder_path, param[1])
        	  files.append(('other_files[]', param[1], open(fp, 'r').read()))
        	  fields.append(param)
        else:
            fields.append(param)

@ui.in_background
def open_file(p):
    console.open_in(p)
    view.close()

# clear temp docverter directory of old output files
temp_dir = os.path.abspath('docverter/')
if os.path.exists(temp_dir):
    shutil.rmtree(temp_dir)
    os.mkdir(temp_dir)
else:
    os.mkdir(temp_dir)
    
view = ui.load_view()
scrollview = view['scrollview1']
clear_vars()
# Work around for segmented text bug
scrollview['from'].action = set_from
scrollview['to'].action = set_to
# end workaround
set_from(scrollview['from'])
set_to(scrollview['to'])
to_pdf_epub_docx(scrollview['toswitch'])   
view.present('popover')