MediaWiki talk:User:Pi zero/Dialog/receive

Instructions for javascript use of this module
For each dialog action, its page-specific javascript should import this code, as follows. The imported code recovers parameters passed to the action, and passes them to a callback that implements action-specific behavior. It also handles origin authentication, action delegation, restoration of dialog field contents if the user navigates away from a page view and comes back to it, and discarding of least-recently-used per-page-view dialog data.

Anonymous callback
Use the following pattern. /* For. See Special:WhatLinksHere/. */

$.getScript( // MediaWiki:Dialog/receive   mw.config.get('wgScript') + '?title=' + mw.util.wikiUrlencode('MediaWiki:Dialog/receive') +                                '&action=raw&ctype=text/javascript',    function  {        window.wikidialog.receiveAnonymous(function  { ...       });    } ); The argument to   is called, with   an object whose fields are the data passed to the action by the calling button. The first argument to the callback is an object containing authenticated information about the request for the current action; authentication is explained below. Ordinarily there are no additional arguments to the callback; however, if  takes additional arguments beyond the callback, these are passed on to the callback as additional arguments.

The name "receiveAnonymous" flags out the callback's responsibility to do its own checking and enforcement of any desired incoming authentication constraints.

Outgoing authentication
To register authentication for action requests from the current page, use either  or. Use  if page content is drawn from another page (hereafter, remote page), specifying the name of the other page as an argument to the function; use   if all the current page content is local.

Either function first authenticates the origin of the current action request, based on all occurrences of dialog/require origin or dialog/null requirement. There must be at least one occurrence of one of these templates, and the conditions set by all such occurrences must be satisfied. also takes an optional argument specifying whether or not the remote page is fully protected. (The current page is already known fully protected, since a button targeted it.) If all performed checks succeed, the function registers authentication information to be passed on by requests from the current page. also performs a useful function even if authentication fails, registering the name of the remote page so it can be passed on (typically to be made accessible by the recipient via special template parameter ).

Either function ( or  ) takes one or two callbacks as optional trailing arguments, the first of these to be called if and when authentication registration is completed, the second to be called if it fails.

Outgoing action requests authenticated via  identify the remote page as their origin and the current page as their proxy. Outgoing action requests authenticated via  identify the current page as their origin and have no proxy.

The two outgoing authentication request functions,  and , also indicate that the current url is conducting dialog activity. This may be important metadata for the rollback facility, if the current activity involves dialog state that would need reconstruction but the current url does not imply an incoming dialog request.

Incoming authentication
When  calls the callback function, it passes as the first argument an object with optional fields   and. These fields contain authentication information registered for the incoming action request. If no such information was successfully registered for the incoming request, the fields are undefined.

To allow an arbitrary origin but require it to be authenticated, test directly for presence of an  in the first argument to the callback; the templates do not directly support this limited constraint. dialog/require origin requires a list of permissible authenticated origins, while dialog/null requirement does not require that the origin be authenticated.

Dialog field recovery
An action can make dialog fields on its page robust against navigating away and coming back, by calling. If any dialog fields are set up by the action, it should set them up before calling, since the function only restores values of dialog fields that exist when it is called. The function is also responsible for arranging a handler to save dialog field values when the user navigates away from the page view, so dialog field values will only be navigation-robust if the dialog fields are either specific to an action page that uses, or viewed through a proxy action that uses. The function is also responsible for discarding least-recently-used dialog-page-view data.

Dialog notes
Internal notices about an action request that may be of diagnostic interest may be stored by passing each notice to ; each notice is automatically html-disabled. A mildly formatted concatenation of all current notices can be retrieved via. The current cache of notices can be purged via. Ordinarily the current cache of notices is purged automatically during delegation, but this automatic purge can be prevented by calling  immediately before.

For example, this module internally caches an explanatory notice when declining outgoing authentication; and the do action caches notices about its handling of action-sequences. Such information may be meaningless to most users, but valuable to someone trying to debug a dialog.

Dialog notes can be observed through the diagnostic panel, and can also be embedded on a page via dialog/notes (which is suported by the do action via ).

Action delegation
An action can generate a fresh request to itself modifying the current incoming request, by calling. All data passed to the current incoming request, including parameters and incoming authentication information, are retained except as overridden.

Basic call format has three arguments: first the primary function of the current action, which is called to produce the action instead of reloading the page; second an object whose fields are dialog data to be modified when delegating; third a function for transforming the action metadata. The final, transforming function takes a single object as argument, with fields,  , and   for the preexisting action's unauthenticated source and authenticated source, and returns an object with these same metadata for the delegation action; fields omitted from the result are understood to be blank. The final, transforming function may be omitted, in which case the metadata is not modified during delegation, but this is not recommended since it doesn't document what is being done; better to provide an explicit identity function,.

An optional fourth metadata field,, is an array of names of fields that are "carried over" &mdash; that is, explicitly passed unchanged &mdash; across the delegation. Ordinarily, the geometry of an input box (its scroll position and size) are reset on delegation; however, geometry of carried-over visible input boxes is preserved.

A variant function, supporting rollback of the delegation in case of low-level failure, is called.

Reserved dialog parameter  is set by. If not otherwise specified,  is cleared on non-rollback delegation. Alternatively,  sets , while   does not alter it.


 * Design notes: An early version of the function(s) supported delegation to a different action.  The additional functionality caused severe complexity in the implementation of the function, with some remarkably inscrutable code that was a great relief to remove after it became clear that delegation within a single action was the important operation.  If delegation to a different action were wanted, the recommended technique would be to construct a hidden button with all the appropriate fields built in and automatically click it (a technique used, as of this writing, by Dialog and Dialog/do). The default   behavior on non-rollback delegation is to make no claims, on grounds that default behavior should minimize potential damage.  The   facility has proven occasionally useful in practice, mitigating concerns on whether it was worth the moderately increased complication of the javascript interface. Geometry is saved only on delegation.  Saving geometry on same-page non-delegating button calls would have required duplicating the &mdash; rather extensive &mdash; geometry-saving code in the gadget, where additional code is discouraged.

Page query
An action can query information about a page by calling. A "fields" object passed in to the function indicates fields to be queried: of possible fields supported, only those present in the fields object on input are determined by the query. A callback passed in to the function is called when the query attempt is completed, regardless of whether it succeeds or fails; results of the query attempt are placed in the fields object and it is passed to the callback.

Supported fields for determination are: , a boolean value;  , the normalized page name;   and   of the current revision;  , a boolean indicating whether the page is fully protected against both editing and moving;  , either "current", "pending", or "never"; and  , with the categories delimited by double quotes and separated by spaces.

If query processing fails, field  is set to an error message and no other field values can be relied upon. If field  is not requested, and the page does not exist, that is an error; if   is requested but false, no other field values can be relied upon.


 * Design note: A trial upgrade provided limited caching within this function, but was found to produce scarcely perceptible speedup in exchange for significantly increased code complexity, particularly in the area of cache purging; the upgrade was rejected.  Calls to this function are a relatively minor component of time-consumption.  Remaining internet accesses are pretty much inherent in what is being done, and the recommended way to achieve major time savings would be to change what is being done, rather than fooling around with details of how it's done (such as caching).

Protection check
A page can be checked to verify that it exists and is fully protected by calling. Its first argument is the name of the page to be checked. Its second argument, if provided, is a function to be called if the verification succeeds, hence if the page is verified to exist and be fully protected. Its third argument, if provided, is a function to be called if the verification fails; a string argument to the failure callback describes the cause of failure.

Template parameters substitution
A wiki markup text can be transformed; substituting for template parameters using given bindings for incoming dialog parameters, and processing calls to dialog/init; by calling. Its first argument is the name of the page on which the text is to be treated as if it occurs; second, an object whose fields are the presumed incoming dialog parameters; third, the wiki markup string to be transformed; fourth, a callback to which the transformed string is passed. Alternatively, an optional argument may be inserted between the second and third; see below. There is also a much simpler version of the function available; see below.

Template parameters are ignored if they contain nesting; thus,  would allow substitution for   but not for.

Two kinds of incoming dialog parameters are handled specially, based on their names. An incoming dialog parameter whose name begins with an upper-case letter and contains no lower-case letters is reserved; one whose name begins with  is local. Before any other processing, reserved and local parameters are deleted from the bindings object provided. Next, certain reserved parameters are added, as detailed below. Then template parameters are substituted for. Finally, dialog/init calls are processed, ignoring any that specify reserved parameters (but local parameters are fine, and this is the only way local parameters can be provided). The ordering of template parameter substitution and dialog/init processing can be partially interleaved in certain special cases involving queries with complicated interfaces, detailed below.

Reserved dialog parameters, if required to substitute for template parameters, are provided based on context rather than merely copying from the bindings object provided. is assigned the name of the page from which the action request came. is assigned a non-blank value if the incoming action request is authenticated, otherwise it isn't assigned a value. is assigned an -separated and -delimited list of incoming parameters that have just been explicitly passed by a button, distinguishing explicit button action from parameters merely carried along by delegation. is assigned the name of the Wikimedia account on which the user is editing, or blank if the user is not logged in. is assigned the names of all user groups on the wiki to which the current user belongs, separated by spaces. is assigned true or false depending on existence of the page named by the provided binding of ; , the raw wiki markup content of that page;  , the timestamp of the most recent revision of that page;  , the names of all categories to which that page belongs; and  , the flaggedrevs status of that page &mdash; never, pending, or current. Version-identification strings are also provided for the dialog gadget and for the current module (receive), under names  and. If the caller provides a value for reserved parameter  (through the optional argument described below), and its value names an existing page, then reserved parameter   is assigned the raw wiki markup content of that page, with inclusion directives processed for transclusion. During an ongoing sequence of actions,  is assigned the number of additional actions permitted in the sequence. If any local parameters were removed from the provided bindings object, their values are provided in reserved parameters, which the name of each local parameter converted to upper case and prefixed with. If the dialog stack is non-empty, reserved parameter  is assigned the number of dialog states currently on the stack.

Several sets of reserved parameters are based on over-the-internet queries with complex interfaces, and the complexities are specified using local parameters. To accommodate this arrangement, dialog/init call processing is done in two tiers: first, after all other template parameters are substituted for, dialog/init calls are processed that don't involve these query-based reserved template parameters; the queries are performed as needed; and finally the remaining dialog/init calls are processed.

If  and   are both non-blank, revision history information for the page named by   can be assigned to certain reserved template parameters starting with. The query can be modulated by and. Information on up to fifty revisions is queried and, if successful, placed into reserved parameters, , , , , and ; in each reserved parameter, the data are separated by. If there are more revisions after the ones reported, contains a value that can be used in  to query further revisions.

If  and   are both non-blank, members of the category named by   can be assigned to certain reserved template parameters starting with. The query can be modulated by, , , and. Information on up to fifty members is queried and, if successful, placed into reserved parameters, , and ; in each reserved parameter, the data are separated by. If there are more members after the ones reported, contains a value that can be used in  to query further members.

If  is non-blank, its template-expansion is assigned on demand to reserved template parameter.

If  and   are both non-blank, file information about the file named by   can be assigned to reserved template parameters starting with. Basic information on the size of the unscaled image is provided in reserved template parameters, , and. File metadata can also be queried through reserved template parameters starting with, as provided by the API through ; as of this writing, these metadata fields aren't well documented, but see mw:API:Imageinfo.

An optional extra argument may be inserted between the second and third; it should be an object, formatted as the fields argument to, requesting data regardless of whether the corresponding template parameters occur. A field  requests parameter , and so on. The extra argument can also be used to specify additional reserved parameter assignments; any binding of a reserved parameter in the extra argument is copied into the incoming bindings. Typically a version-identification string is provided for the calling action, such as.

A much simpler transformation is available by calling. Its first argument is an object whose fields are the presumed incoming dialog parameters, and its second argument is the wiki markup string to be transformed. The specified parameters are substituted for template parameters in the wiki markup string.


 * Design notes: Because fetching a preload page is expensive, a pseudo-template was considered as an inexpensive alternative, preprocessed (similarly to dialog/init) to return its template argument unexpanded.  However, the pseudo-template would put the raw material in the dialog page itself, where it could not be unprotected without unprotecting the dialog; and its use would be fragile since the scope of the pseudo-template call would be delimited by double-braces.  Given these limitations, the pseudo-template was deemed not worth the additional interface complexity. The interleaved processing of dialog/init calls and reserved template parameters was approached cautiously, to avoid creating political pressures for future progressive loss of simplicity, and thus useability and maintainability.  To this end, the interleaving was minimized commensurate with certain specific objectives:  (1) a complex API interface with the same look-and-feel as the complex API interface of the do verb edit; (2) queries controlled strictly by the local markup of the page itself, as would be true of template parameters alone; and (3) ability to channel all template parameters through dialog/init for unformatted use in initializing text input fields.  The only inter-parameter dependencies introduces by the interleaving are strictly required for these objectives. Function   supports substitution of dialog parameters for template parameters in preview, design for which is discussed at Template:Dialog/preview/doc.

Html safety
A string can be rendered safe for insertion in html via function. Its argument is the string to be sanitized, and its result is a "safe" string; angle brackets in the string are replaced by  and , thereby preventing surreptitious insertion of html tags. This is an important safety measure when arbitrary strings (usually, dialog parameters) are inserted directly into html for display on the page, which is commonly done when displaying error messages. Most non-error cases are already safe because material inserted into the page (by, for example, the do action) has been output by the wiki parser, which produces safe html.

For example, one might have

Inclusion directive processing
Raw wiki markup can contain inclusion directives &mdash;,  ,   &mdash; modulating which parts apply when the markup is transcluded to another page versus which apply when the markup occurs directly on the local page. Function  processes these directives to produce just the parts that apply when transcluded on another page. Its one argument is the raw wiki markup to be processed. It does no other processing besides inclusion directives, stopping short of template expansion (which would require a server call and would therefore be an expensive operation, whereas merely processing inclusion directives can be done client-side).

Incoming action request validation
Function  returns a boolean indicating whether or not the page has been arrived at through a dialog action request. It is used internally by  to decide whether the dialog action page has actually been invoked or is merely being viewed. It is also useful for determining whether or not query parameters embedded in the url should be converted into a dialog action request; see action do url conversion and the standalone url conversion action.

Internally, each action request (within a logical browser session) has a unique ID number, which is used to store data associated with that request, such as incoming dialog parameters. Such internal storage is encapsulated within the dialog gadget, the current module (receive), and necessarily the diagnostic panel. Ordinarily, the ID number is embedded in the url of the action request; naturally, it doesn't change when delegating an action request within the same action. The dialog tools are designed primarily to work with the ID number embedded in the url, and the standalone url conversion action works by jumping to a fresh url with an embedded ID. However, action do can also operate directly with a url that has query parameters but no embedded ID. Without the embedded ID, navigating away from the action request and then naively back to it will usually cause the software to lose track of what ID it was using, so that the earlier dialog data cannot be recovered (except perhaps laboriously through the diagnostic panel). The rollback facility should be able to recover dialog state from a url without embedded ID, if the activity was flagged by use of an outgoing authentication function; in such a case, the rollback facility assumes that the unembedded ID was one less than the next ID maintained by the dialog software.

Metadata stored under each dialog ID includes the url of the action request associated with that ID; that metadata is stored by a button when clicked (regardless of whether the button is delegating), so its presence under the current dialog ID indicates that the current action was initiated by a button click, and this is what function  checks for.

Rollback
Special facilities support rollback of an action request to the previous dialog state from which the request was issued. Rollback is intended primarily to avoid catastrophic data loss due to a low-level (API) failure, such as inability to read an edit form or inability to perform the low-level edit operation initiated by a mediating edit form. Rollback is not primarily envisioned as a response to a dialog-level logical decision, such as when an edit form loads correctly but then refuses to initiate the requested edit because of some condition specified on the form; those sorts of error should preferentially be handled within the dialog framework, although rollback may be a last resort for some situations whose handling is fumbled in-dialog. (However, rollback does also form the technical medium for view confirmation.)

Rollback may be "simple", of a request from a different url; or "delegating", of a delegated request. To determine whether or not rollback is currently possible, call, which returns a boolean.

Rollback when possible is initiated by calling, which returns a boolean indicating whether rollback appears to have been successfully initiated; a function argument must be provided suitable as the first argument to   (although this argument is actually used only for delegating rollback). Rollback is disabled by calling, which erases the rollback data; or disabled when a further action request is issued.

A simple request can be rolled back unless the requesting button used dialog/button template parameter. A delegating request can be rolled back only if the requester performed delegation by calling alternative function.


 * Design note: Robust maintainability of the software calls for simple, error-retardant logic.
 * Rollback data is kept separately for the two cases, simple and delegating. Both are kept strictly separate from all other stored values (such as dialog field recovery data; although when actually rolling back, field values are restored by feeding them into the dialog field recovery mechanism).
 * Each of the two kinds of rollback data is only written by a single function: simple-rollback data only by the button handler of the gadget, delegating-rollback data only by internal function , whose public interface is through functions   and  .
 *  takes responsibility for removing simple-rollback data as appropriate.  However, the gadget's only provision for rollback is storing the simple-rollback data (which only takes a single line); this keeps the delegating-rollback data handling entirely encapsulated within the receive module.  To preserve consistency, in all rollback-related code in the receive module that doesn't erase'' simple-rollback data, simple-rollback data disables delegating rollback and causes erasure of delegating-rollback data.

Stack
A dialog state can be saved and come back to later, using functions  and. These states are preserved for as long as they're on the stack, separately from the set of most-recently-used states maintained by function. As of this writing, the maximum stack size is half the size of 's most-recently-used set (changing automatically if the later size parameter is adjusted).

Function  attempts to save the previous dialog state onto the stack. It can only do so if rollback to the previous state is still possible, the state change from previous to current state was non-delegating, and the stack is not yet full. If the function fails to push the previous state, it returns a string explaining why.

Function  attempts to remove the topmost dialog state from the stack and resume it. It returns true if successful, false if unsuccessful.


 * Design note: This is an extremely straightforward-to-implement facility that, amongst other possible uses, empowers wiki contributors to provide meta-dialog facilities:  while using a dialog one might suspend it to enter a meta-dialog for modifying the dialog one was just using, then pop back into the dialog having modified it.  All the state saving and restoring are handled by other facilities already in place; only the id of the previous state (to prevent it from being deallocated) and its url (to jump to when popping) need to be recorded on the stack.  In contrast, if one wanted to support pushing a delegated state, the implementation would be enormously complicated with no other facilities to help, and would introduce lots of strongly coupling with other mechanisms; the degradation of simplicity of implementation is certainly not worth the benefit given that an alternative solution for push/pop is available, and probably wouldn't be worth the benefit even if there weren't an alternative solution available.

Dialog installation
Installation of the dialog software on a wikimedia project involves the following elements. Some internal details of the software were not initially written with full project-generality built into them; pockets not yet generalized may remain. Ancestral Category:Dialog infrastructure attempts to gather together everything needed (barring mundane general wiki infrastructure &mdash; things like template tl). The tools currently assume that the name of the local project space is  (for example, here it is  ). When importing each page, check for associated documentation and subpages, adjust for local differences in categorization (customizing dialog/subtemplates cat takes care of much of that), and impose suitable page protections (sometimes tricky). Assistants are arranged under a separate ancestor, Category:Interactive assistants, with some overlap.
 * A conditional statement in MediaWiki:Common.js that, on every page load, checks for a page-specific javascript file, and loads it if found. Likewise in MediaWiki:Mobile.js.
 * This is a very small surgical change, but profoundly transforms the role of javascript in project customization because, in essence, it allows certain select wiki pages to be verbs rather than nouns. Page-specific javascript won't impact load time for any wiki page other than the one it's specific to, and will work for any user, even an IP.  Naming conventions for page-specific javascript may have to vary between projects due to possible conflicts; these variations should be handled on ordinary wiki pages by dialog/js prefix.


 * The dialog gadget.
 * Recommended this be at the top of MediaWiki:Gadgets-definition; make it opt-in at first by omitting the  option, then once the installation is satisfactorily complete and working correctly make it opt-out.  The gadget is the only substantial dialog javascript that is run unconditionally, rather than page-specifically.  It causes dialog elements to be visible on the page, and enables dialog buttons on the page so they can make dialog-field content available for use by page-specific javascript.


 * The receive module.
 * This is provided for use by page-specific javascript, to access data passed through a button by the dialog gadget. Also provides a number of related facilities to help clients remain independent of internal details of dialog data-passing implementation.


 * Dialog formatting templates.
 * These embed information on a wiki page for use by the dialog gadget and receive module. The user perceives these templates as "doing" much of the work of the dialog software, because all instructions to the dialog gadget and receive module are encoded using these templates, even though internally the templates are "just" cosmetic.


 * Dialog actions.
 * As of this writing, one multi-purpose action is provided for doing pretty much everything, because moving from one action to another is expensive (it's expected to add about one second to access time). There are two specialized action-like devices &mdash; diagnostic panel and url-to-dialog converter &mdash; and some legacy actions retained as illustrations.  A minimal test case is action xyzzy.


 * evalx.
 * This complements the primitive dialog software, by providing powerful facilities to succinctly manipulate the contents of wiki pages from within wiki markup, so such manipulations are available for use in interactive dialogs.


 * Assistants.
 * These are sets of pages that use dialog to aid human users in performing various tasks; essentially, . Although many assistants may be specific to a particular project, some are expected to be of interest for any project at all (for example, assistants for building and maintaining assistants).

Recommended miscellany:
 * Add to MediaWiki:Protect-dropdown an item "Dialog edit form, authenticating form, or action" (or equivalent).
 * Though not dialog infrastructure, Category:Preload templates, Category:Editintro templates (or equivalent).