]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blobdiff - doc/plugins/write.mdwn
po/todo: update
[git.ikiwiki.info.git] / doc / plugins / write.mdwn
index 1b78f5900b2de71ee10c4a4bd94f17c8c6d62bf1..fff142fa20b5f539673579218e0d2a43312c459c 100644 (file)
@@ -19,7 +19,7 @@ that can be fleshed out to make a useful plugin.
 `IkiWiki::Plugin::pagecount` is another simple example. All perl plugins
 should `use IkiWiki` to import the ikiwiki plugin interface. It's a good
 idea to include the version number of the plugin interface that your plugin
 `IkiWiki::Plugin::pagecount` is another simple example. All perl plugins
 should `use IkiWiki` to import the ikiwiki plugin interface. It's a good
 idea to include the version number of the plugin interface that your plugin
-expects: `use IkiWiki 2.00`.
+expects: `use IkiWiki 3.00`.
 
 An external plugin is an executable program. It can be written in any
 language. Its interface to ikiwiki is via XML RPC, which it reads from
 
 An external plugin is an executable program. It can be written in any
 language. Its interface to ikiwiki is via XML RPC, which it reads from
@@ -55,8 +55,8 @@ plugin, and a "call" parameter, which tells what function to call for the
 hook.
 
 An optional "last" parameter, if set to a true value, makes the hook run
 hook.
 
 An optional "last" parameter, if set to a true value, makes the hook run
-after all other hooks of its type. Useful if the hook depends on some other
-hook being run first.
+after all other hooks of its type, and an optional "first" parameter makes
+it run first. Useful if the hook depends on some other hook being run first.
 
 ## Types of hooks
 
 
 ## Types of hooks
 
@@ -196,7 +196,6 @@ generating the page.
 
        hook(type => "pagetemplate", id => "foo", call => \&pagetemplate);
 
 
        hook(type => "pagetemplate", id => "foo", call => \&pagetemplate);
 
-
 [[Templates|wikitemplates]] are filled out for many different things in
 ikiwiki, like generating a page, or part of a blog page, or an rss feed, or
 a cgi. This hook allows modifying the variables available on those
 [[Templates|wikitemplates]] are filled out for many different things in
 ikiwiki, like generating a page, or part of a blog page, or an rss feed, or
 a cgi. This hook allows modifying the variables available on those
@@ -322,6 +321,41 @@ This hook should avoid directly redirecting the user to a signin page,
 since it's sometimes used to test to see which pages in a set of pages a
 user can edit.
 
 since it's sometimes used to test to see which pages in a set of pages a
 user can edit.
 
+### cansave
+
+       hook(type => "cansave", id => "foo", call => \&cansave);
+
+This hook can be used to implement arbitrary access methods to control
+when a page being edited can be saved using the web interface (commits
+from revision control bypass it).
+
+When a page is about to be saved, each registered cansave hook is
+called in turn, and passed the page name, the edited content, a CGI
+object and a session object.
+
+The return value of a cansave hook is interpreted the same as for the
+canedit hook.
+
+### canremove
+
+       hook(type => "canremove", id => "foo", call => \&canremove);
+
+This hook can be used to implement arbitrary access methods to control when
+a page can be removed using the web interface (commits from revision control
+bypass it). It works exactly like the `canedit` hook.
+
+### canrename
+
+       hook(type => "canrename", id => "foo", call => \&canrename);
+
+This hook can be used to implement arbitrary access methods to control when
+a page can be renamed using the web interface (commits from revision control
+bypass it). It works exactly like the `canedit` and `canremove` hook,
+but is passed:
+* a CGI object
+* a session object
+* the named parameters `src`, `srcfile`, `dest` and `destfile`.
+
 ### editcontent
 
        hook(type => "editcontent", id => "foo", call => \&editcontent);
 ### editcontent
 
        hook(type => "editcontent", id => "foo", call => \&editcontent);
@@ -361,14 +395,29 @@ This hook is called whenever ikiwiki normally saves its state, just before
 the state is saved. The function can save other state, modify values before
 they're saved, etc.
 
 the state is saved. The function can save other state, modify values before
 they're saved, etc.
 
-### renamepage
+### renamelink
 
 
-       hook(type => "renamepage", id => "foo", call => \&renamepage);
+       hook(type => "renamelink", id => "foo", call => \&renamelink);
 
 This hook is called by the [[plugins/rename]] plugin when it renames
 
 This hook is called by the [[plugins/rename]] plugin when it renames
-something. The hook is passed named parameters: `page`, `oldpage`,
-`newpage`, and `content`, and should try to modify the content to reflect
-the name change. For example, by converting links to point to the new page.
+something, once per page linking to the renamed page's old location.
+The hook is passed named parameters: `page`, `oldpage`, `newpage`, and
+`content`, and should try to modify the content of `page` to reflect
+the name change. For example, by converting links to point to the
+new page.
+
+### rename
+
+       hook(type => "rename", id => "foo", call => \&renamepages);
+
+When a page or set of pages is renamed, the referenced function is
+called, and is passed:
+
+* a reference to an array of hashes with keys: `src`, `srcfile`,
+  `dest`, `destfile`, `required`. Such a hook function can modify
+  the array.
+* a CGI object
+* a session object
 
 ### getsetup
 
 
 ### getsetup
 
@@ -432,7 +481,7 @@ describes the plugin as a whole. For example:
 
 To import the ikiwiki plugin interface:
 
 
 To import the ikiwiki plugin interface:
 
-       use IkiWiki '2.00';
+       use IkiWiki '3.00';
 
 This will import several variables and functions into your plugin's
 namespace. These variables and functions are the ones most plugins need,
 
 This will import several variables and functions into your plugin's
 namespace. These variables and functions are the ones most plugins need,
@@ -487,7 +536,7 @@ use the following hashes, using a page name as the key:
   destination file.
 * `%pagesources` contains the name of the source file for each page.
 
   destination file.
 * `%pagesources` contains the name of the source file for each page.
 
-Also, the %IkiWiki::version variable contains the version number for the
+Also, the `%IkiWiki::version` variable contains the version number for the
 ikiwiki program.
 
 ### Library functions
 ikiwiki program.
 
 ### Library functions
@@ -697,11 +746,15 @@ This can be called when creating a new page, to determine what filename
 to save the page to. It's passed a page name, and its type, and returns
 the name of the file to create, relative to the srcdir.
 
 to save the page to. It's passed a page name, and its type, and returns
 the name of the file to create, relative to the srcdir.
 
-#### `targetpage($$)`
+#### `targetpage($$;$)`
 
 Passed a page and an extension, returns the filename that page will be
 rendered to.
 
 
 Passed a page and an extension, returns the filename that page will be
 rendered to.
 
+Optionally, a third parameter can be passed, to specify the preferred
+filename of the page. For example, `targetpage("foo", "rss", "feed")`
+will yield something like `foo/feed.rss`.
+
 ## Miscellaneous
 
 ### Internal use pages
 ## Miscellaneous
 
 ### Internal use pages
@@ -821,6 +874,30 @@ it up in the history.
 
 It's ok if this is not implemented, and throws an error.
 
 
 It's ok if this is not implemented, and throws an error.
 
+#### `rcs_receive()`
+
+This is called when ikiwiki is running as a pre-receive hook (or
+equivalent), and is testing if changes pushed into the RCS from an
+untrusted user should be accepted. This is optional, and doesn't make
+sense to implement for all RCSs.
+
+It should examine the incoming changes, and do any sanity 
+checks that are appropriate for the RCS to limit changes to safe file adds,
+removes, and changes. If something bad is found, it should exit
+nonzero, to abort the push. Otherwise, it should return a list of
+files that were changed, in the form:
+
+       {
+               file => # name of file that was changed
+               action => # either "add", "change", or "remove"
+               path => # temp file containing the new file content, only
+                       # needed for "add"/"change", and only if the file
+                       # is an attachment, not a page
+       }
+
+The list will then be checked to make sure that each change is one that
+is allowed to be made via the web interface.
+
 ### PageSpec plugins
 
 It's also possible to write plugins that add new functions to
 ### PageSpec plugins
 
 It's also possible to write plugins that add new functions to
@@ -847,3 +924,82 @@ to a hash containing all the config items. They should also implement a
 By the way, to parse a ikiwiki setup file and populate `%config`, a
 program just needs to do something like:
 `use IkiWiki::Setup; IkiWiki::Setup::load($filename)`
 By the way, to parse a ikiwiki setup file and populate `%config`, a
 program just needs to do something like:
 `use IkiWiki::Setup; IkiWiki::Setup::load($filename)`
+
+### Function overriding
+
+Sometimes using ikiwiki's pre-defined hooks is not enough. Your plugin
+may need to replace one of ikiwiki's own functions with a modified version,
+or wrap one of the functions.
+
+For example, your plugin might want to override `displaytime`, to change
+the html markup used when displaying a date. Or it might want to override
+`IkiWiki::formattime`, to change how a date is formatted. Or perhaps you
+want to override `bestlink` and change how ikiwiki deals with WikiLinks.
+
+By venturing into this territory, your plugin is becoming tightly tied to
+ikiwiki's internals. And it might break if those internals change. But
+don't let that stop you, if you're brave.
+
+Ikiwiki provides an `inject()` function, that is a powerful way to replace
+any function with one of your own. This even allows you to inject a
+replacement for an exported function, like `bestlink`. Everything that
+imports that function will get your version instead. Pass it the name of
+the function to replace, and a new function to call. 
+
+For example, here's how to replace `displaytime` with a version using HTML 5
+markup:
+
+       inject(name => 'IkiWiki::displaytime', call => sub {
+               return "<time>".formattime(@_)."</time>";
+       });
+
+Here's how to wrap `bestlink` with a version that tries to handle
+plural words:
+
+       my $origbestlink=\&bestlink;
+       inject(name => 'IkiWiki::bestlink', call => \&mybestlink);
+
+       sub deplural ($) {
+               my $word=shift;
+               $word =~ s/e?s$//; # just an example :-)
+               return $word;
+       }
+
+       sub mybestlink ($$) {
+               my $page=shift;
+               my $link=shift;
+               my $ret=$origbestlink->($page, $link);
+               if (! length $ret) {
+                       $ret=$origbestlink->($page, deplural($link));
+               }
+               return $ret;
+       }
+
+### Javascript
+
+Some plugins use javascript to make ikiwiki look a bit more web-2.0-ish.
+
+All javascript code should be put in `.js` files in the `javascript`
+underlay, and plugins using those files can enable use of the underlay by
+calling `add_underlay("javascript");` in their `import` function.
+
+You'll have to arrange for `<script>` tags to be added to the pages that
+use your javascript. This can be done using a `format` hook.
+
+Ikiwiki provides some utility functions in `ikiwiki.js`, for use by other
+javascript code. These include:
+
+#### `getElementsByClass(cls, node, tag)` 
+
+Returns an array of elements with the given class. The node and tag are
+optional and define what document node and element names to search.
+
+#### `hook(name, call)`
+
+The function `call` will be run as part of the hook named `name`.
+
+Note that to hook into `window.onload`, you can use the `onload' hook.
+
+#### `run_hooks(name)`
+
+Runs the hooks with the specified name.