| t | | t | |
| <table align="right"><tr><td><div class="toc"> | | |
| Contents: | | |
| <ul> | | |
| <li><a href="#Introduction">Introduction</a></li> | | |
| <li><a href="#Name_and_Location">Name and Location</a></li> | | |
| <li><a href="#Declaration_in_a_TBWiki_Page">Declaration in a TBWiki Page</a></li> | | |
| <li><a href="#Interface_from_TBWiki_to_the_processor">Interface from TBWiki to the processor</a></li> | | |
| <ul> | | |
| <li><a href="#main()_function">main() function</a></li> | | |
| <li><a href="#help()_function">help() function</a></li> | | |
| <li><a href="#other_functions_("action"_functions)">other functions ("action" functions)</a></li> | | |
| </ul> | | |
| <li><a href="#Interface_from_the_processor_to_TBWiki">Interface from the processor to TBWiki</a></li> | | |
| <ul> | | |
| <li><a href="#request_object">request object</a></li> | | |
| <li><a href="#req_functions">req functions</a></li> | | |
| <li><a href="#tbwiki_functions">tbwiki functions</a></li> | | |
| <li><a href="#return_value">return value</a></li> | | |
| </ul> | | |
| <li><a href="#Example_Processor_-_FooReplace">Example Processor - FooReplace</a></li> | | |
| <ul> | | |
| <li><a href="#FooReplace_processor_code">FooReplace processor code</a></li> | | |
| <li><a href="#FooReplace_processor_invocation">FooReplace processor invocation</a></li> | | |
| <li><a href="#FooReplace_processor_result">FooReplace processor result</a></li> | | |
| </ul> | | |
| <li><a href="#Actions">Actions</a></li> | | |
| <ul> | | |
| <li><a href="#Action_invocation">Action invocation</a></li> | | |
| <ul> | | |
| <li><a href="#Reading_the_processor_block_content">Reading the processor block content</a></li> | | |
| <li><a href="#Reading_config_values">Reading config values</a></li> | | |
| </ul> | | |
| <li><a href="#Action_output">Action output</a></li> | | |
| </ul> | | |
| <li><a href="#Action_Sample_-_UserChoice">Action Sample - UserChoice</a></li> | | |
| <ul> | | |
| <li><a href="#UserChoice_processor_code">UserChoice processor code</a></li> | | |
| <li><a href="#UserChoice_processor_invocation">UserChoice processor invocation</a></li> | | |
| <li><a href="#UserChoice_processor_result">UserChoice processor result</a></li> | | |
| <li><a href="#UserChoice_processor_action_outcome">UserChoice processor action outcome</a></li> | | |
| </ul> | | |
| </ul> | | |
| </div></td></tr></table> | | |
| <h1><a name="Introduction">Introduction</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Introduction">edit section</a>]</font></span> | | |
| </h1> | | |
| TBWiki supports two kinds of extension mechanisms: "macros" and "processors". | | |
| <p> | | |
| There are a few builtin macros, but add-on macros and processors | | |
| can be created and are "run" when a page is parsed and sent by TBWiki. | | |
| <p> | | |
| The function of both of these extension mechanisms (or plugins) is | | |
| to allow for dynamic creation of page content at the time a page | | |
| is read by a user. Thus, these act like a kind of embedded CGI-script | | |
| inside of the TBWiki framework. | | |
| <p> | | |
| In general, Macros are used for simple transformations of content | | |
| or for page-related content creation. Processors are for doing | | |
| more complicated processing of page or wiki data, possibly requiring | | |
| configuration settings or multiple interactions with the user. | | |
| <p> | | |
| <h1><a name="Name_and_Location">Name and Location</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Name_and_Location">edit section</a>]</font></span> | | |
| </h1> | | |
| By convention, the name of a processor is in CamelCase (words strung | | |
| together with the first letter of each word capitalized). | | |
| <p> | | |
| Plugin processors are placed in the <code>data/plugin</code> | | |
| directory. They are python files and must have a filename starting with | | |
| the "Processor", then the processor name, and ending in the extension | | |
| ".py". For example the "Foo" processor would have the path and filename | | |
| <p> | | |
| <code>/data/plugin/ProcessorFoo.py</code> | | |
| <p> | | |
| <h1><a name="Declaration_in_a_TBWiki_Page">Declaration in a TBWiki Page</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Declaration_in_a_TBWiki_Page">edit section</a>]</font></span> | | |
| </h1> | | |
| A processor is declared on a tbwiki page with the syntax: | | |
| <pre> | | |
| {{{#!Foo | | |
| configuration lines | | |
| and content lines | | |
| }} } | | |
| </pre> | | |
| <p> | | |
| The processor name in the declaration must match the | | |
| name part of the filename for the processor module | | |
| in the plugin directory. The lines inside the processor | | |
| block can consist of anything, and are parsed and processed | | |
| by the processor itself. (That is, they are not interpreted | | |
| by TBWiki engine, and are specific to the processor being invoked.) | | |
| <p> | | |
| <h1><a name="Interface_from_TBWiki_to_the_processor">Interface from TBWiki to the processor</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Interface_from_TBWiki_to_the_processor">edit section</a>]</font></span> | | |
| </h1> | | |
| A processor must be an importable python module, with some specifically-named | | |
| function definitions. The TBWiki calls functions in the processor to perform | | |
| actions, usually resulting the transformation or creation of new content that | | |
| will be returned to the user as part of the page where the processor is | | |
| declared. | | |
| <p> | | |
| <h2><a name="main()_function">main() function</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=main()_function">edit section</a>]</font></span> | | |
| </h2> | | |
| A processor must define a function called "main()". As a page is rendered by TBWIKI, when the processor definition is encountered in the wiki page, TBWiki | | |
| calls the 'main' function to invoke the processor functionality. | | |
| <p> | | |
| This "main" function takes two arguments, which are | | |
| the request object and the content block string. | | |
| <p> | | |
| The processor operates on (i.e. processes) the content data, possibly using the | | |
| information and functions provided in the request object, and | | |
| returns a string of HTML data, for output as part of the returned page. | | |
| <p> | | |
| The block containing the processor declaration inside the page is | | |
| replaced by TBWiki with the result of executing the processor. | | |
| <p> | | |
| <h2><a name="help()_function">help() function</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=help()_function">edit section</a>]</font></span> | | |
| </h2> | | |
| If a processor defines the special function "help()", then the system can | | |
| provide online help for the processor, for a page displaying the SystemInfo. | | |
| This function is accessed via a URL with the name: <page_url>?action=<processor_name>.help | | |
| <p> | | |
| <h2><a name="other_functions_("action"_functions)">other functions ("action" functions)</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=other_functions_("action"_functions)">edit section</a>]</font></span> | | |
| </h2> | | |
| In general, any of the functions in the processor can be accessed using | | |
| a URL that includes the name of a page that declares the processor, the | | |
| processor name, and the function name. So if a page "Some_Page" had | | |
| a declaration of processor "Foo" on it, that defined a function "bar", then | | |
| the URL for causing the invocation of that function would be: | | |
| <p> | | |
| <pre> | | |
| ../SomePage?action=Foo.bar | | |
| </pre> | | |
| <p> | | |
| These are referred to as "action functions" (or just "actions"), in this | | |
| documentation. | | |
| <p> | | |
| Action functions are used to implement state machines or complex | | |
| processors, which require multiple interactions with the user, or | | |
| to display multiple pages in sequence (such as a blog or an image gallery). | | |
| <p> | | |
| See the <a href="#Actions">#Actions</a> section below for more details. | | |
| <p> | | |
| <h1><a name="Interface_from_the_processor_to_TBWiki">Interface from the processor to TBWiki</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Interface_from_the_processor_to_TBWiki">edit section</a>]</font></span> | | |
| </h1> | | |
| <h2><a name="request_object">request object</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=request_object">edit section</a>]</font></span> | | |
| </h2> | | |
| The request object has all the data available to tbwiki about the request | | |
| for this page. This includes the page_name, the entire tbwiki config, and | | |
| other stuff. | | |
| <p> | | |
| Here are some pertinent data fields that some processors use: | | |
| <p> | | |
| <ul><li>req.form = the CGI form data for the request (in the format provided by the python cgi module) | | |
| </ul> | | |
| <p> | | |
| <ul><li>req.page_filename = filename (including full path) of the requested page | | |
| <li>req.page_name = name of the requested page | | |
| <li>req.config = configuration settings for the wiki | | |
| <ul><li>req.config.data_dir = location in the local file system where the data | | |
| pages are located. | | |
| </ul><li>req.data = data values (and data value functions) for this wiki | | |
| <ul><li>req.data.version - version of the tbwiki engine | | |
| <li>req.data.timestamp - timestamp string for the current time | | |
| <li>and many more | | |
| </ul> | | |
| </ul> | | |
| <p> | | |
| <h2><a name="req_functions">req functions</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=req_functions">edit section</a>]</font></span> | | |
| </h2> | | |
| <ul><li>req.add_to_message() - a function to add to the status message for the page. | | |
| This is often used for debugging purposes, since it appears separately from | | |
| the page content | | |
| <li>req.html_error() - show a string in red on the page | | |
| <li>req.block_to_html() - convert a block of text from tbwiki markup to HTML | | |
| <li>req.parse_conf() - used to parse configuration items from a block of text | | |
| </ul> | | |
| <p> | | |
| <h2><a name="tbwiki_functions">tbwiki functions</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=tbwiki_functions">edit section</a>]</font></span> | | |
| </h2> | | |
| In some cases, it is necessary to load the tbwiki_engine module itself | | |
| into the processor module, in order to access global module functions | | |
| or data. Here are some tbwiki_engine functions or data that might be useful | | |
| for a processor: | | |
| <ul><li>tbwiki_engine.make_url() | | |
| <li>tbiki_engine.parse_state = state used for processing lines during page parsing | | |
| <li>tbiki_engine.show_line() = function used to parse a line of TBWIKI-format text and convert it into HTML output (which is printed by show_line) | | |
| </ul> | | |
| <p> | | |
| <h2><a name="return_value">return value</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=return_value">edit section</a>]</font></span> | | |
| </h2> | | |
| The processor's main() function should return a string consisting of HTML | | |
| to be output as part of the returned page HTML. | | |
| <p> | | |
| If you want markup processed in the content string, you must process it | | |
| yourself. Usually, this means you would do whatever processing on the | | |
| content is appropriate for your processor, then call | | |
| req.block_to_html(content), and return the result of that. | | |
| <p> | | |
| <h1><a name="Example_Processor_-_FooReplace">Example Processor - FooReplace</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Example_Processor_-_FooReplace">edit section</a>]</font></span> | | |
| </h1> | | |
| Here is sample code for a very simple processor: | | |
| <p> | | |
| <h2><a name="FooReplace_processor_code">FooReplace processor code</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=FooReplace_processor_code">edit section</a>]</font></span> | | |
| </h2> | | |
| This would be in the file ProcessorFooReplace.py | | |
| <pre> | | |
| import re | | |
| | | |
| def main(req, content): | | |
| result = re.sub("foo", "bar", content) | | |
| return result | | |
| </pre> | | |
| <p> | | |
| <h2><a name="FooReplace_processor_invocation">FooReplace processor invocation</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=FooReplace_processor_invocation">edit section</a>]</font></span> | | |
| </h2> | | |
| To use this processor, a user would place the following block on a page: | | |
| <p> | | |
| <pre> | | |
| {{{#!FooReplace | | |
| This text has foo, but it (foo) should be replaced with 'bar'. | | |
| </pre> | | |
| }}} | | |
| <p> | | |
| <h2><a name="FooReplace_processor_result">FooReplace processor result</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=FooReplace_processor_result">edit section</a>]</font></span> | | |
| </h2> | | |
| Here is what the resulting output would look like on the page: | | |
| <p> | | |
| <pre> | | |
| This text has bar, but it (bar) should be replaced with 'bar'. | | |
| </pre> | | |
| <p> | | |
| <h1><a name="Actions">Actions</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Actions">edit section</a>]</font></span> | | |
| </h1> | | |
| You can cause the engine to invoke different functions in your processor. | | |
| This is useful for handling a flow of operations requiring sequential | | |
| displays or multiple user inputs. | | |
| <p> | | |
| To have the engine call a particular function in your processor, | | |
| put the function name in the action portion of the the URL for some | | |
| link, button or form element that is selected by the user for you system. | | |
| The specific syntax is: | | |
| <pre> | | |
| base_url/?action=<processor_name>.<action> | | |
| </pre> | | |
| <p> | | |
| That is, specify the value for the 'action' argument in the URL | | |
| as the processor name, followed by a period, followed by the name of | | |
| the action function inside that processor to call. | | |
| <p> | | |
| <h2><a name="Action_invocation">Action invocation</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Action_invocation">edit section</a>]</font></span> | | |
| </h2> | | |
| Action functions for your processor are invoked differently from | | |
| the processor's <code>main()</code> function. | | |
| <p> | | |
| When an action function is specified in a URL to the TBWiki engine, the | | |
| page in the URL is not rendered. Instead, the processor is called, | | |
| with the request object only. If the content of the processor block is | | |
| needed, or some other arguments are needed (e.g. passed from some other | | |
| processor function to this one), then those need to loaded or transferred | | |
| using some other mechanism. This is usually done by passing session-specific | | |
| arguments on the URL used to activate the action. | | |
| <p> | | |
| <h3><a name="Reading_the_processor_block_content">Reading the processor block content</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Reading_the_processor_block_content">edit section</a>]</font></span> | | |
| </h3> | | |
| A action function does not receive the content block | | |
| automatically, as one of its arguments. However, it is common | | |
| for an action function to need to read the content of the processor block. | | |
| For example, the processor content block is often where the configuration | | |
| for the processor is stored. | | |
| <p> | | |
| One way to accomplish this is to pass the block_name of the processor block | | |
| to the action function, as part of the action URL. | | |
| <p> | | |
| in main: | | |
| <pre> | | |
| def main(req, content): | | |
| block_name = req.state.block_name | | |
| # add the block name to the URL, like so: | | |
| link = ...?action=Foo.bar&block_name=" + block_name | | |
| </pre> | | |
| <p> | | |
| in an action function: | | |
| <pre> | | |
| def bar(req): | | |
| block_name = req.form["block_name"].value | | |
| content = req.get_page_item(block_name) | | |
| # parse content as needed | | |
| </pre> | | |
| <p> | | |
| <h3><a name="Reading_config_values">Reading config values</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Reading_config_values">edit section</a>]</font></span> | | |
| </h3> | | |
| Some processors need to handle both configuration settings and content. | | |
| This is true, for example, of the Table processor, which has table definition | | |
| and display settings, as well as the actual content to be placed in the | | |
| table. | | |
| <p> | | |
| One convention used to support this is to have configuration lines at | | |
| the top of the processor block content, followed by a dashed line | | |
| (a line consisting of only 3 dashes), like so: | | |
| <pre> | | |
| --- | | |
| </pre> | | |
| <p> | | |
| Here is an example showing configuration content in the same processor block. | | |
| <p> | | |
| <pre> | | |
| {{{#!ColoredTimer | | |
| color=red | | |
| duration=10m30s | | |
| interval=5s | | |
| ---- | | |
| Here is a timer: | | |
| << {{HTML(<font color=red>missing data value "timer"</font>)}} >> | | |
| It should be counting down. | | |
| } }} | | |
| </pre> | | |
| <p> | | |
| Assuming you have the processor block content in the variable "content", | | |
| you could use the following lines to parse this into two parts, including | | |
| a configuration map (a python dictionary containing config items). | | |
| <pre> | | |
| config_str, content_str = content.split("---\n") | | |
| config_map = req.parse_conf(config_str) | | |
| # do something with content_str (based on settings in config_map) | | |
| </pre> | | |
| <p> | | |
| <h2><a name="Action_output">Action output</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Action_output">edit section</a>]</font></span> | | |
| </h2> | | |
| Unlike your main processor function, action functions are not | | |
| called in "page context". That is, an action function does | | |
| NOT return output to be placed on the page in place of the block, | | |
| during page rendering. | | |
| <p> | | |
| Rather, when the function is entered, no html has been emitted yet | | |
| -- no header information, nav bars, nor even the "Content-type:" line. | | |
| Thus they have complete control to emit any HTML output they want. | | |
| <p> | | |
| This is usually done by calling <code>req.show_header()</code> with some custom | | |
| title to reflect the action or operation being performed. Then | | |
| the HTML for the page is printed directly by the action function. | | |
| <p> | | |
| Note that if your routine calls <code>req.show_header()</code> to output a standard | | |
| wiki page header (with the current theme), then <code>req.show_footer()</code> is called after the processor action routine. However, if the action routine | | |
| does not call <code>req.show_header()</code>, then <code>req.show_footer()</code> will not be | | |
| called automatically, and it is up to the action routine to complete the HTML output for the request. | | |
| <p> | | |
| <h1><a name="Action_Sample_-_UserChoice">Action Sample - UserChoice</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=Action_Sample_-_UserChoice">edit section</a>]</font></span> | | |
| </h1> | | |
| Here is sample code for a simple processor that shows what choice | | |
| of two items a user selected. The choices are on two lines in the | | |
| block content. | | |
| <p> | | |
| <h2><a name="UserChoice_processor_code">UserChoice processor code</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=UserChoice_processor_code">edit section</a>]</font></span> | | |
| </h2> | | |
| This would be in the file ProcessorUserChoice.py | | |
| <pre> | | |
| def UserChoice(req, content): | | |
| lines = content.split("\n") | | |
| if len(lines)<2: | | |
| return "ERROR: not enough lines in UserChoice processor block" | | |
| link1 = req.page_url + "?action=UserChoice.choice1" | | |
| link2 = req.page_url + "?action=UserChoice.choice2" | | |
| html = """Please choose one of the following: | | |
| <ul> | | |
| <li><a href="%s">%s</a> | | |
| <li><a href="%s">%s</a> | | |
| </ul>""" % (link1, lines[0], link2, lines[1]) | | |
| return result | | |
| | | |
| def choice1(req): | | |
| req.show_header("User Choice result") | | |
| | | |
| result = "You chose choice1 - this is inside the wiki page and theme" | | |
| print result | | |
| | | |
| def choice2(req): | | |
| html = """Content-type: text/html | | |
| | | |
| <body bgcolor="yellow"> | | |
| <h1>User Choice result</h1> | | |
| """ | | |
| | | |
| html += "You chose choice2 - this is outside the wiki page and theme" | | |
| html += "<br> and it is bright yellow!" | | |
| html += "</body>" | | |
| print html | | |
| | | |
| </pre> | | |
| <p> | | |
| <h2><a name="UserChoice_processor_invocation">UserChoice processor invocation</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=UserChoice_processor_invocation">edit section</a>]</font></span> | | |
| </h2> | | |
| To use this processor, a user would place the following block on a page: | | |
| <p> | | |
| <pre> | | |
| Stuff before the processor block | | |
| | | |
| {{{#!UserChoice | | |
| This is the first option: apples. | | |
| This is the second option: bananas. | | |
| } }} | | |
| | | |
| Stuff after the processor block | | |
| </pre> | | |
| <p> | | |
| <h2><a name="UserChoice_processor_result">UserChoice processor result</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=UserChoice_processor_result">edit section</a>]</font></span> | | |
| </h2> | | |
| Here is what the resulting output (from main) would look like on the page: | | |
| <p> | | |
| Stuff before the processor block | | |
| <p> | | |
| Please choose one of the following: | | |
| <p> | | |
| <ul><li><a href="/tbwiki/DocProcessors?action=UserChoice.choice1">This is the first option: apples.</a><li><a href="/tbwiki/DocProcessors?action=UserChoice.choice2">This is the first second option: bananas.</a></ul><p> | | |
| Stuff after the processor block | | |
| <p> | | |
| <h2><a name="UserChoice_processor_action_outcome">UserChoice processor action outcome</a> | | |
| <span align=right class="section_edit_link">[<a href="/tbwiki/DocProcessors?action=edit§ion=UserChoice_processor_action_outcome">edit section</a>]</font></span> | | |
| </h2> | | |
| <p> | | |
| Here is what would be displayed if the user selected the 'apples' option: | | |
| <pre> | | |
| You chose choice 1 - this is inside the wiki page and theme | | |
| </pre> | | |
| <p> | | |