Editorial Workflows

Sidebar Live ToC

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: NOTE: This workflow is designed for iPad only.

NOTE: For the hyperlinking to work, this requires a workflow called "Select Range", that passes values such as "2:4" to the "Select Range" command.

Shows table of contents, based on headings, for the current document in a sidebar panel, next to the editor.

The preview is updated automatically as you type, and it preserves its scroll position.

Links that you tap on in the preview select the corresponding heading in the document.

Shared by: @ClareMacraeUK

Comments: Comment Feed (RSS)

@ClareMacraeUK — 27 Dec 2014
Please be sure to load the [Select Range](http://www.editorial-workflows.com/workflow/5613124300308480/4e9WdOYWf8w) workflow before running this!

+ Add Comment

Workflow Preview
Run Python Script ?
Source Code
#coding: utf-8
import ui
import editor

# Used to make links open in the browser panel:
class WebViewDelegate (object):
	def webview_should_start_load(self, webview, url, nav_type):
		if nav_type == 'link_clicked':
			import webbrowser
			webbrowser.open(url)
			return False
		return True
		
class SidebarView (ui.View):
	@ui.in_background

	def refresh(self):
		if not self.active:
			# Sidebar was already closed, don't refresh anymore
			return
		# Import these again because it's possible that another
		# script has run in the meantime:
		import ui, editor
		import markdown2
		import re
		text = editor.get_text()
				
		# Only refresh if the text has changed since last time:
		if text != self.current_text:

			if self.first_run:
				# In the first run, just load the template...
				html = \
					'<!DOCTYPE html><html><head><meta http-equiv="Content-Type" ' \
					'content="text/html; charset=utf-8"><style>body ' + \
					'{font-family:helvetica; font-size: 16px;} ' + \
					'a {color: #000080; text-decoration: none;}'

				heading_levels = [1, 2, 3, 4, 5, 6]
				for level in heading_levels:
					html += \
						'h%s {font-size: 16px; font-weight: normal; ' \
						'line-height: 1.0; margin-top: 0em; margin-bottom: 1em; margin-left: %sem;} ' \
						% (str(level), str(level-1))

				html += \
					'</style></head><body><div id="content">Loading...</div>' \
					'<div style="height:400px"></div></body></html>'
				self['webview1'].load_html(html)
			else:
				# ...afterwards, replace the HTML via JavaScript, so that the
				# scroll position is preserved:

				# I tried putting this in a function, and Editorial crashed later on,
				# probably because the function returned Null

				# NB This requires a workflow "Select Range" that takes characters e.g. 5:10 to
				#    indicate the required selection.
				# TODO Add a run-time check that a workflow with this name exists
				url_part_base = u'editorial://?command=Select%%20Range&input=%s'

				# Extract all the level 1-6 markdown headings
				lines = text.split(u'\n')
				summary_text = u''
				current_pos = 0

				# TODO Only match up to 6 # characters
				heading_regexp = re.compile("^(#+[ 	]*)(.*)")

				for line in lines:
					match = heading_regexp.match(line)
					if match != None:
						line_selection = str(current_pos) + ':' + str(current_pos + len(line))

						link_text = match.group(2)
						link_text = link_text.strip()

						# Escape any []() in the text from the heading
						link_text = link_text.replace('[', '\\[')
						link_text = link_text.replace(']', '\\]')

						# Create hyperlink to jump to this position in the file
						url = url_part_base % line_selection
						hypertext_link = u'[%s](%s)' % (link_text, url)

						# Add this line to the output
						summary_text += match.group(1) + hypertext_link + u'\n'

					current_pos += len(line) + 1

				# Convert our selection from the document into html
				html = markdown2.markdown(summary_text)
				html = html.replace('"', '\\"').replace('\n', '\\n')

				# Display the HTML
				js = 'document.getElementById("content").innerHTML = "%s";' % html
				self['webview1'].evaluate_javascript(js)
				self.current_text = text

		ui.delay(self.refresh, 0.5 if self.first_run else 1.5)
		self.first_run = False
	
	def did_load(self):
		self.active = True
		self.first_run = True
		self.current_text = ''
		self.refresh()
	
	def will_close(self):
		self.active = False

def main():
	import platform
	if not platform.machine().startswith('iPad'):
		import console 
		console.alert('iPad Required',
			            'Sorry, this workflow is designed for iPad only.', 'OK',
			            hide_cancel_button=True)
		return
	v = ui.load_view()
	v['webview1'].delegate = WebViewDelegate()
	v.present('sidebar')

main()