[Pieforms-commit] SF.net SVN: pieforms: [105] pieforms-php5/trunk/src/pieform.php
Status: Alpha
Brought to you by:
oracleshinoda
|
From: <ora...@us...> - 2006-12-23 03:36:12
|
Revision: 105
http://svn.sourceforge.net/pieforms/?rev=105&view=rev
Author: oracleshinoda
Date: 2006-12-22 19:36:11 -0800 (Fri, 22 Dec 2006)
Log Message:
-----------
* Updated the comment on the Pieform class to better reflect the API changes being made
* Only include the JSON library when json_encode is first called
* Moved all of the user-configurable flags for the class into one member variable, 'data'.
* Renamed the ajaxsuccessfunction and ajaxfailurefunction to *callback for consistency
* Made the cancel function optional
* Made setting $element['goto'] actually work, for both normal forms and AJAX forms
* Fixed all submit-based elements to have their value placed in the submit data if they are
pressed.
* AJAX submission is now no longer strictly AJAX - instead, data is submitted to a hidden
iframe. This removes all of the mess around the pieform_get_value_js_[element] functions,
and allows sending files (which works fine, even for more than one file).
* Now all replies by JSON should be done using the $form->json_reply method, which understands
how to reply to a hidden iframe.
* Defined some constants for use with $form->json_reply
* Full i18n is now built in. Each element can export its own strings, and the user can override
them on a per element or per form basis (even for all forms in their application with the
pieform_configure function).
* API changes:
- Renamed pieform_configure_[element] to pieform_element_[element]_configure
- Submit functions now take the Pieform object as their first parameter (major BC break!)
- pieform_render_element now takes its parameters in reverse order (although this function is
largely an internal-only function)
- Renamed pieform_get_value_[element] to pieform_element_[element]_get_value
- Renamed pieform_render_[element] to pieform_element_[element] (major BC break!)
- pieform_element_[element] functions now takes the Pieform object as their first parameter (major BC break!)
Modified Paths:
--------------
pieforms-php5/trunk/src/pieform.php
Modified: pieforms-php5/trunk/src/pieform.php
===================================================================
--- pieforms-php5/trunk/src/pieform.php 2006-12-18 01:12:20 UTC (rev 104)
+++ pieforms-php5/trunk/src/pieform.php 2006-12-23 03:36:11 UTC (rev 105)
@@ -37,22 +37,22 @@
* <pre>
* $form = array(
* 'name' => 'myform',
- * 'action' => '/myscript.php',
+ * 'action' => 'myscript.php',
* 'method' => 'post',
* 'elements' => array(
* // definition of elements in the form
* )
* );
*
- * $smarty->assign('myform', form($form));
+ * $smarty->assign('myform', pieform($form));
*
- * function myform_validate($form, $values) {
+ * function myform_validate(Pieform $form, $values) {
* // perform validation agains form elements here
* // some types of validation are conveniently available already as
* // as part of the form definition hash
* }
*
- * function myform_submit($values) {
+ * function myform_submit(Pieform $form, $values) {
* // perform action knowing that the values are valid, e.g. DB insert.
* }
* </pre>
@@ -66,22 +66,22 @@
//
// @todo stuff to do for forms:
//
- // - more form element types (inc. types like autocomplete and date picker and wyswiyg)
+ // - more form element types (inc. types like autocomplete and wyswiyg)
// - support processing of data before validation occurs (e.g. trim(), strtoupper())
// - Basic validation is possible as there's a callback function for checking,
// but some helper functions could be written to make people's job validating
// stuff much easier (form_validate_email, form_validate_date etc).
// - Collapsible js for fieldsets
// - Grippie for textareas
- // - javascript validation
+ // - javascript validation (probably won't be done as ajax validation is pretty good)
// - handle multipage forms?
// - handle a tabbed interface type of form?
//
}
if (!function_exists('json_encode')) {
+ require_once 'JSON/JSON.php';
function json_encode($data) {
- require_once 'JSON/JSON.php';
$json = new Services_JSON();
return $json->encode($data);
}
@@ -96,24 +96,16 @@
* Represents an HTML form. Forms created using this class have a lot of the
* legwork for forms abstracted away.
*
- * The form API makes it really easy to build complex HTML forms, simply by
+ * Pieforms makes it really easy to build complex HTML forms, simply by
* building a hash describing your form, and defining one or two callback
* functions.
*
- * For more information on how the form API works, please see the documentation
+ * For more information on how Pieforms works, please see the documentation
* at https://eduforge.org/wiki/wiki/mahara/wiki?pagename=FormAPI
*/
class Pieform {
/**
- * Data for the form
- *
- * @var array
- * @todo move all of the member fields here into this field
- */
- private $data = array();
-
- /**
* Maintains a tab index across all created forms, to make it easy for
* people to forget about it and have it just work for all of their forms.
*
@@ -129,131 +121,16 @@
private $name = '';
/**
- * The method that the form will be submitted by. Either 'get' or 'post'.
+ * Data for the form
*
- * @var string
- */
- private $method = 'get';
-
- /**
- * The URL that the form will be submitted to.
- *
- * @var string
- */
- private $action = '';
-
- /**
- * Whether the form should be validated. Forms that are not validated are
- * also not submitted. This is useful if you just want to draw a form, and
- * have no validation rules apply to it.
- */
- private $validate = true;
-
- /**
- * Whether the form should be checked for submission. Forms can have
- * validate on and submit off in order to validate submitted data, but to
- * not bother with the submit.
- *
- * @var bool
- */
- private $submit = true;
-
- /**
- * Whether to submit the form via ajax
- *
- * @todo rename this probably, because AJAX GET is supported too
- *
- * @var bool
- */
- private $ajaxpost = false;
-
- /**
- * A callback to call before submitting the form via AJAX
- *
- * @var string
- */
- private $preajaxsubmitcallback = '';
-
- /**
- * A callback to call after submitting the form via AJAX, regardless of
- * the result of the submission
- *
- * @var string
- */
- private $postajaxsubmitcallback = '';
-
- /**
- * Name of a javascript function to call on successful ajax submission
- *
- * @var string
- */
- private $ajaxsuccessfunction = '';
-
- /**
- * Name of a javascript function to call on failed ajax submission
- *
- * @var string
- */
- private $ajaxfailurefunction = '';
-
- /**
- * The tab index for this particular form.
- *
- * @var int
- */
- private $tabindex = 1;
-
- /**
- * Directories to look for elements, renderers and rules
- *
* @var array
*/
- private $configdirs = array();
+ private $data = array();
/**
- * Whether to autofocus fields in this form, and if so, optionally which
- * field to focus.
- *
- * @var mixed
- */
- private $autofocus = false;
-
- /**
- * The renderer used to build the HTML for the form that each element sits
- * in. See the form/renderer package to find out the allowed types.
- *
- * @var string
- */
- private $renderer = 'table';
-
- /**
- * The language used for form rule error messages.
- *
- * @var string
- */
- private $language = 'en.utf8';
-
- /**
- * Language strings for rules
- *
- * @var array
- */
- private $language_strings = array(
- 'en.utf8' => array(
- 'required' => 'This field is required',
- 'email' => 'E-mail address is invalid',
- 'maxlength' => 'This field must be at most %d characters long',
- 'minlength' => 'This field must be at least %d characters long',
- 'integer' => 'The field must be an integer',
- 'validateoptions' => 'The option "%s" is invalid',
- 'regex' => 'This field is not in valid form'
- )
- );
-
- /**
* Whether this form includes a file element. If so, the enctype attribute
* for the form will be specified as "multipart/mixed" as required. This
- * is auto-detected by the Form class.
+ * is auto-detected by the Pieform class.
*
* @var bool
*/
@@ -268,30 +145,6 @@
private $submitted = false;
/**
- * Whether the form is cancellable or not - that is, whether sending a
- * request to cancel the form will be honoured or not. This is useful for
- * the transient login form, where it must pass on cancel requests from
- * other forms sometimes.
- *
- * @var bool
- */
- private $iscancellable = true;
-
- /**
- * Name of validate function
- *
- * @var string
- */
- private $validatefunction = '';
-
- /**
- * Name of submit function
- *
- * @var string
- */
- private $submitfunction = '';
-
- /**
* Processes the form. Called by the {@link pieform} function. It simply
* builds the form (processing it if it has been submitted), and returns
* the HTML to display the form
@@ -335,101 +188,81 @@
// Assign defaults for the form
$formdefaults = array(
- 'method' => 'get',
- 'action' => '',
- 'ajaxpost' => false,
+ 'method' => 'get',
+ 'action' => '',
+ 'elements' => array(),
+ 'renderer' => 'table',
+ 'ajaxform' => false,
'preajaxsubmitcallback' => '',
'postajaxsubmitcallback' => '',
- 'ajaxsuccessfunction' => '',
- 'ajaxfailurefunction' => '',
- 'configdirs' => array(),
- 'autofocus' => false,
- 'language' => 'en.utf8',
+ 'ajaxsuccesscallback' => '',
+ 'ajaxfailurecallback' => '',
'validate' => true,
'submit' => true,
- 'elements' => array(),
- 'submitfunction' => '',
- 'validatefunction' => '',
+ 'validatecallback' => '',
+ 'submitcallback' => '',
+ 'iscancellable' => true,
+ 'autofocus' => false,
+ 'configdirs' => array(),
+ 'language' => 'en.utf8',
+ 'rulei18n' => array(),
+ 'tabindex' => false
);
$data = array_merge($formdefaults, $formconfig, $data);
$this->data = $data;
// Set the method - only get/post allowed
- $data['method'] = strtolower($data['method']);
- if ($data['method'] != 'post') {
- $data['method'] = 'get';
+ $this->data['method'] = strtolower($data['method']);
+ if ($this->data['method'] != 'post') {
+ $this->data['method'] = 'get';
}
- $this->method = $data['method'];
- $this->action = $data['action'];
- $this->validate = $data['validate'];
- $this->submit = $data['submit'];
- $this->configdirs = array_map(
- create_function('$a', 'return substr($a, -1) == "/" ? substr($a, 0, -1) : $a;'),
- (array) $data['configdirs']);
- $this->autofocus = $data['autofocus'];
- $this->language = $data['language'];
-
- if ($data['submitfunction']) {
- $this->submitfunction = $data['submitfunction'];
- }
- else {
- $this->submitfunction = $this->name . '_submit';
- }
- if ($data['validatefunction']) {
- $this->validatefunction = $data['validatefunction'];
+ // Make sure that the javascript callbacks are valid
+ if ($this->data['ajaxform']) {
+ $this->validate_js_callbacks();
}
- else {
- $this->validatefunction = $this->name . '_validate';
- }
- if ($data['ajaxpost']) {
- $this->ajaxpost = true;
- $this->preajaxsubmitcallback = self::validate_js_callback($data['preajaxsubmitcallback']);
- $this->postajaxsubmitcallback = self::validate_js_callback($data['postajaxsubmitcallback']);
- // @todo rename to *callback instead of *function for consistency
- $this->ajaxsuccessfunction = self::validate_js_callback($data['ajaxsuccessfunction']);
- $this->ajaxfailurefunction = self::validate_js_callback($data['ajaxfailurefunction']);
+ if (!$this->data['validatecallback']) {
+ $this->data['validatecallback'] = $this->name . '_validate';
}
- if (isset($data['renderer'])) {
- $this->renderer = $data['renderer'];
+ if (!$this->data['submitcallback']) {
+ $this->data['submitcallback'] = $this->name . '_submit';
}
- if (isset($data['tabindex'])) {
- $this->tabindex = intval($data['tabindex']);
- }
- else {
- $this->tabindex = self::$formtabindex++;
- }
+ $this->data['configdirs'] = array_map(
+ create_function('$a', 'return substr($a, -1) == "/" ? substr($a, 0, -1) : $a;'),
+ (array) $this->data['configdirs']);
- $this->iscancellable = (isset($data['iscancellable']) && !$data['iscancellable']) ? false : true;
- if (!is_array($data['elements']) || count($data['elements']) == 0) {
+ if (empty($this->data['tabindex'])) {
+ $this->data['tabindex'] = self::$formtabindex++;
+ }
+
+ if (!is_array($this->data['elements']) || count($this->data['elements']) == 0) {
throw new PieformException('Forms must have a list of elements');
}
// Remove elements to ignore
- foreach ($data['elements'] as $name => $element) {
+ foreach ($this->data['elements'] as $name => $element) {
if (isset($element['type']) && $element['type'] == 'fieldset') {
foreach ($element['elements'] as $subname => $subelement) {
if (!empty($subelement['ignore'])) {
- unset ($data['elements'][$name]['elements'][$subname]);
+ unset ($this->data['elements'][$name]['elements'][$subname]);
}
}
}
else {
if (!empty($element['ignore'])) {
- unset($data['elements'][$name]);
+ unset($this->data['elements'][$name]);
}
}
}
- $this->elements = $data['elements'];
-
// Set some attributes for all elements
$autofocusadded = false;
- foreach ($this->elements as $name => &$element) {
+ foreach ($this->data['elements'] as $name => &$element) {
+ // @todo re-check ordering of this section
// The name can be in the element itself. This is compatibility for the perl version
if (isset($element['name'])) {
$name = $element['name'];
@@ -449,12 +282,13 @@
}
if ($element['type'] == 'file') {
$this->fileupload = true;
- if ($this->method == 'get') {
- $this->method = 'post';
+ if ($this->data['method'] == 'get') {
+ $this->data['method'] = 'post';
self::info("Your form '$this->name' had the method 'get' and also a file element - it has been converted to 'post'");
}
}
if ($element['type'] == 'fieldset') {
+ $this->include_plugin('element', 'fieldset');
foreach ($element['elements'] as $subname => &$subelement) {
// The name can be in the element itself. This is compatibility for the perl version
if (isset($subelement['name'])) {
@@ -470,32 +304,12 @@
. $name . '" has no value');
}
}
- if (!isset($subelement['title'])) {
- $subelement['title'] = '';
- }
- if ($subelement['type'] == 'file') {
- $this->fileupload = true;
- if ($this->method == 'get') {
- $this->method = 'post';
- self::info("Your form '$this->name' had the method 'get' and also a file element - it has been converted to 'post'");
- }
- }
- if (!$autofocusadded && $this->autofocus === true) {
- $subelement['autofocus'] = true;
- $autofocusadded = true;
- }
- else if (!empty($this->autofocus) && $this->autofocus !== true
- && $subname == $this->autofocus) {
- $subelement['autofocus'] = true;
- }
- $subelement['name'] = $subname;
- $subelement['tabindex'] = $this->tabindex;
- // Let each element set and override attributes if necessary
+ // Configure some basics for real elements
if ($subelement['type'] != 'markup') {
// This function can be defined by the application using Pieforms,
// and applies to all elements of this type
- $function = 'pieform_configure_' . $subelement['type'];
+ $function = 'pieform_element_' . $subelement['type'] . '_configure';
if (function_exists($function)) {
$subelement = $function($subelement);
}
@@ -503,65 +317,100 @@
// This function is defined by the plugin itself, to set fields on
// the element that need to be set but should not be set by the
// application
- $function = 'pieform_render_' . $subelement['type'] . '_set_attributes';
+ $function = 'pieform_element_' . $subelement['type'] . '_set_attributes';
$this->include_plugin('element', $subelement['type']);
if (function_exists($function)) {
$subelement = $function($subelement);
}
+
+ // Add the autofocus flag to the element if required
+ if (!$autofocusadded && $this->data['autofocus'] === true && empty($element['nofocus'])) {
+ $subelement['autofocus'] = true;
+ $autofocusadded = true;
+ }
+ else if (!empty($this->data['autofocus']) && $this->data['autofocus'] !== true
+ && $subname == $this->data['autofocus']) {
+ $subelement['autofocus'] = true;
+ }
+
+ // All elements should have some kind of title
+ if (!isset($subelement['title'])) {
+ $subelement['title'] = '';
+ }
+
+ // Force the form method to post if there is a file to upload.
+ if ($subelement['type'] == 'file') {
+ $this->fileupload = true;
+ if ($this->data['method'] == 'get') {
+ $this->data['method'] = 'post';
+ self::info("Your form '$this->name' had the method 'get' and also a file element - it has been converted to 'post'");
+ }
+ }
+
+ // All elements inherit the form tabindex
+ $subelement['tabindex'] = $this->data['tabindex'];
}
+ $subelement['name'] = $subname;
+
}
}
else {
- if (!$autofocusadded && $this->autofocus === true) {
- $element['autofocus'] = true;
- $autofocusadded = true;
- }
- elseif (!empty($this->autofocus) && $this->autofocus !== true
- && $name == $this->autofocus) {
- $element['autofocus'] = true;
- }
- $element['name'] = $name;
- $element['tabindex'] = $this->tabindex;
- }
+ // Let each element set and override attributes if necessary
+ if ($element['type'] != 'markup') {
+ $function = 'pieform_element_' . $element['type'] . '_configure';
+ if (function_exists($function)) {
+ $element = $function($element);
+ }
- // Let each element set and override attributes if necessary
- if ($element['type'] != 'markup') {
- $function = 'pieform_configure_' . $element['type'];
- if (function_exists($function)) {
- $element = $function($element);
- }
+ $function = 'pieform_element_' . $element['type'] . '_set_attributes';
+ $this->include_plugin('element', $element['type']);
+ if (function_exists($function)) {
+ $element = $function($element);
+ }
- $function = 'pieform_render_' . $element['type'] . '_set_attributes';
- $this->include_plugin('element', $element['type']);
- if (function_exists($function)) {
- $element = $function($element);
+ // Add the autofocus flag to the element if required
+ if (!$autofocusadded && $this->data['autofocus'] === true && empty($element['nofocus'])) {
+ $element['autofocus'] = true;
+ $autofocusadded = true;
+ }
+ elseif (!empty($this->data['autofocus']) && $this->data['autofocus'] !== true
+ && $name == $this->data['autofocus']) {
+ $element['autofocus'] = true;
+ }
+
+ $element['tabindex'] = $this->data['tabindex'];
}
+ $element['name'] = $name;
}
+
}
// Check if the form was submitted, and if so, validate and process it
- $global = ($this->method == 'get') ? $_GET: $_POST;
- if ($this->validate && isset($global['pieform_' . $this->name] )) {
- if ($this->submit) {
+ $global = ($this->data['method'] == 'get') ? $_GET: $_POST;
+ if ($this->data['validate'] && isset($global['pieform_' . $this->name] )) {
+ if ($this->data['submit']) {
$this->submitted = true;
// Check if the form has been cancelled
- if ($this->iscancellable) {
+ if ($this->data['iscancellable']) {
foreach ($global as $key => $value) {
if (substr($key, 0, 7) == 'cancel_') {
- // Check for and call the cancel function handler
- // @todo<nigel>: it might be that this function could be optional
+ // Check for and call the cancel function handler, if defined
$function = $this->name . '_' . $key;
- if (!function_exists($function)) {
- throw new PieformException('Form "' . $this->name . '" does not have a cancel function handler for "' . substr($key, 7) . '"');
+ if (function_exists($function)) {
+ $function($this);
}
- $function();
+
+ // Redirect the user to where they should go, if the cancel handler didn't already
$element = $this->get_element(substr($key, 7));
if (!isset($element['goto'])) {
throw new PieformException('Cancel element "' . $element['name'] . '" has no page to go to');
}
- // @todo what happens in the case of ajax post?
- redirect($element['goto']);
- return;
+ if ($this->data['ajaxform']) {
+ $this->json_reply(PIEFORM_CANCEL, $element['goto']);
+ }
+ header('HTTP/1.1 303 See Other');
+ header('Location:' . $element['goto']);
+ exit;
}
}
}
@@ -572,32 +421,32 @@
// Perform general validation first
$this->validate($values);
// Then user specific validation if a function is available for that
- if (function_exists($this->validatefunction)) {
- $function = $this->validatefunction;
+ $function = $this->data['validatecallback'];
+ if (function_exists($function)) {
$function($this, $values);
}
// Submit the form if things went OK
- if ($this->submit && !$this->has_errors()) {
+ if ($this->data['submit'] && !$this->has_errors()) {
$submitted = false;
foreach ($this->get_elements() as $element) {
// @todo Rename 'ajaxmessages' to 'submitelement'
if (!empty($element['ajaxmessages']) == true && isset($global[$element['name']])) {
$function = "{$this->name}_submit_{$element['name']}";
if (function_exists($function)) {
- $function($values);
+ $function($this, $values);
$submitted = true;
break;
}
}
}
- if (!$submitted && function_exists($this->submitfunction)) {
- $function = $this->submitfunction;
+ $function = $this->data['submitcallback'];
+ if (!$submitted && function_exists($function)) {
// Call the user defined function for processing a submit
// This function should really redirect/exit after it has
// finished processing the form.
// @todo maybe it should do just that...
- $function($values);
+ $function($this, $values);
// This will only work if I can make the login_submit function stuff work in login_validate
//if ($this->ajaxpost) {
// $message = 'Your ' . $this->name . '_submit function should output some json and exit';
@@ -613,19 +462,18 @@
}
// Auto focus the first element with an error if required
- if ($this->autofocus !== false) {
+ if ($this->data['autofocus'] !== false) {
$this->auto_focus_first_error();
}
// If the form has been submitted by ajax, return ajax
- if ($this->ajaxpost) {
+ if ($this->data['ajaxform']) {
$errors = $this->get_errors();
$json = array();
foreach ($errors as $element) {
$json[$element['name']] = $element['error'];
}
- echo json_encode(array('error' => 'local', 'message' => '@todo allow forms to specify a local error message', 'errors' => $json));
- exit;
+ $this->json_reply(PIEFORM_ERR, '@todo allow forms to specify a local error message', $json);
}
}
}
@@ -652,33 +500,15 @@
}
/**
- * Returns the form submission method
+ * Returns whether the form has been submitted
*
- * @return string
- */
- public function get_method() {
- return $this->method;
- }
-
- /**
- * Is the form being submitted by ajax?
- *
* @return bool
*/
- public function get_ajaxpost() {
- return $this->ajaxpost;
+ public function is_submitted() {
+ return $this->submitted;
}
/**
- * Returns the renderer used on to render the form
- *
- * @return string
- */
- public function get_renderer() {
- return $this->renderer;
- }
-
- /**
* Returns the HTML for the <form...> tag
*
* @return string
@@ -686,7 +516,7 @@
public function get_form_tag() {
$result = '<form';
foreach (array('name', 'method', 'action') as $attribute) {
- $result .= ' ' . $attribute . '="' . $this->{$attribute} . '"';
+ $result .= ' ' . $attribute . '="' . $this->data[$attribute] . '"';
}
$result .= ' id="' . $this->name . '"';
if ($this->fileupload) {
@@ -697,15 +527,6 @@
}
/**
- * Returns whether the form has been submitted
- *
- * @return bool
- */
- public function is_submitted() {
- return $this->submitted;
- }
-
- /**
* Builds and returns the HTML for the form, respecting the chosen renderer.
*
* Note that the "action" attribute for the form tag are NOT HTML escaped
@@ -722,23 +543,23 @@
$result = $this->get_form_tag() . "\n";
}
- $this->include_plugin('renderer', $this->renderer);
+ $this->include_plugin('renderer', $this->data['renderer']);
// Form header
- $function = 'pieform_renderer_' . $this->renderer . '_header';
+ $function = 'pieform_renderer_' . $this->data['renderer'] . '_header';
if (function_exists($function)) {
$result .= $function();
}
// Render each element
- foreach ($this->elements as $name => $elem) {
+ foreach ($this->data['elements'] as $name => $elem) {
if ($elem['type'] != 'hidden') {
- $result .= pieform_render_element($elem, $this);
+ $result .= pieform_render_element($this, $elem);
}
}
// Form footer
- $function = 'pieform_renderer_' . $this->renderer . '_footer';
+ $function = 'pieform_renderer_' . $this->data['renderer'] . '_footer';
if (function_exists($function)) {
$result .= $function();
}
@@ -747,7 +568,7 @@
$this->include_plugin('element', 'hidden');
foreach ($this->get_elements() as $element) {
if ($element['type'] == 'hidden') {
- $result .= pieform_render_hidden($element, $this);
+ $result .= pieform_element_hidden($element, $this);
}
}
$element = array(
@@ -755,15 +576,15 @@
'name' => 'pieform_' . $this->name,
'value' => ''
);
- $result .= pieform_render_hidden($element, $this);
+ $result .= pieform_element_hidden($element, $this);
if ($outputformtags) {
$result .= "</form>\n";
}
- if ($this->ajaxpost) {
- $result .= '<script language="javascript" type="text/javascript">';
- $result .= $this->submit_js();
- $result .= "</script>\n";
+ if ($this->data['ajaxform']) {
+ $result .= '<script type="text/javascript">';
+ $result .= "\n" . $this->submit_js();
+ $result .= "\n</script>\n";
}
return $result;
@@ -777,21 +598,17 @@
* is available for the element.
*/
public function get_value($element) {
- $function = 'pieform_get_value_' . $element['type'];
- // @todo for consistency, reverse parameter order - always a Form object first
+ $function = 'pieform_element_' . $element['type'] . '_get_value';
if (function_exists($function)) {
- return $function($element, $this);
+ return $function($this, $element);
}
- $global = ($this->method == 'get') ? $_GET : $_POST;
+ $global = ($this->data['method'] == 'get') ? $_GET : $_POST;
// If the element is a submit element and has its value in the request, return it
// Otherwise, we don't return the value if the form has been submitted, as they
// aren't normally returned using a standard form.
- if (isset($element['value']) && !empty($element['ajaxmessages']) && isset($global[$element['name']])) {
+ if (isset($element['value'])) {
return $element['value'];
}
- else if (isset($element['value']) && (!$this->is_submitted() || (empty($element['ajaxmessages'])))) {
- return $element['value'];
- }
else if (isset($global[$element['name']]) && $element['type'] != 'submit') {
return $global[$element['name']];
}
@@ -810,7 +627,7 @@
*/
public function get_elements() {
$elements = array();
- foreach ($this->elements as $name => $element) {
+ foreach ($this->data['elements'] as $name => $element) {
if ($element['type'] == 'fieldset') {
foreach ($element['elements'] as $subelement) {
$elements[] = $subelement;
@@ -844,7 +661,7 @@
}
/**
- * Retrieves submitted values from POST for the elements of this form.
+ * Retrieves submitted values from the request for the elements of this form.
*
* This takes into account that some elements may not even have been set,
* for example if they were check boxes that were not checked upon
@@ -857,10 +674,14 @@
*/
private function get_submitted_values() {
$result = array();
- $global = ($this->method == 'get') ? $_GET : $_POST;
+ $global = ($this->data['method'] == 'get') ? $_GET : $_POST;
+ log_debug($global);
foreach ($this->get_elements() as $element) {
if ($element['type'] != 'markup') {
- $result[$element['name']] = $this->get_value($element);
+ if (empty($element['ajaxmessages']) ||
+ !empty($element['ajaxmessages']) && isset($global[$element['name']])) {
+ $result[$element['name']] = $this->get_value($element);
+ }
}
}
return $result;
@@ -901,132 +722,123 @@
}
}
- /**
- * Returns a js function to submit an ajax form
- * Expects formname_message() to be defined by the renderer,
- * and formname_validate() to be defined.
- */
private function submit_js() {
- // @todo nigel should disable all buttons on this form while the submit is happening
- $result = <<<EOF
+ $strprocessingform = get_string('processingform');
-var {$this->name}_btn = null;
-// For each submit button, add a waffer thin flag
-addLoadEvent(function () {
+ $result = "var {$this->name}_btn = null;\n";
-EOF;
+ $connecteventadded = false;
foreach ($this->get_elements() as $element) {
if (!empty($element['ajaxmessages'])) {
- $result .= " connect($('{$this->name}_{$element['name']}'), 'onclick', function () { {$this->name}_btn = '{$element['name']}'; });\n";
+ if (!$connecteventadded) {
+ $result .= "addLoadEvent(function() {\n";
+ $connecteventadded = true;
+ }
+ $result .= " connect($('{$this->name}_{$element['name']}'), 'onclick', function() { {$this->name}_btn = '{$element['name']}'; });\n";
}
}
+ if ($connecteventadded) {
+ $result .= "});\n";
+ }
+
$result .= <<<EOF
+connect($('{$this->name}'), 'onsubmit', function(e) {
+ if (typeof(tinyMCE) != 'undefined') { tinyMCE.triggerSave(); }
-});
-
-connect($('{$this->name}'), 'onsubmit', function (e) {
- // eventually we should check input types for wysiwyg before doing this
- // Also should only save wysiwyg elements in the form, not all of them...
- if (typeof(tinyMCE) != 'undefined') { tinyMCE.triggerSave(); }
-
EOF;
- if (!empty($this->preajaxsubmitcallback)) {
- $result .= " $this->preajaxsubmitcallback();\n";
+ if (!empty($this->data['preajaxsubmitcallback'])) {
+ $result .= " {$this->data['preajaxsubmitcallback']}();\n";
}
$result .= <<<EOF
- var data = {};
+ var iframe = $('{$this->name}_iframe');
+ $('{$this->name}').target = '{$this->name}_iframe';
+ if (!iframe) {
+ iframe = createDOM('iframe', {
+ 'name': '{$this->name}_iframe',
+ 'id' : '{$this->name}_iframe'
+ });
+ hideElement(iframe);
+ insertSiblingNodesAfter($('{$this->name}'), iframe);
+
+ window.pieformHandler_{$this->name} = function(data) {
+ {$this->name}_remove_all_errors();
+ evalJSONRequest(data);
+ if (data.returnCode == 0) {
+ // The request completed successfully
+ {$this->name}_message(data.message, 'ok');
+
EOF;
- // Get values for each element from the form via the DOM
- foreach ($this->get_elements() as $element) {
- // Submit elements will be handled later, as there could be more than one
- if (empty($element['ajaxmessages'])) {
- if ($element['type'] != 'markup') {
- $function = 'pieform_get_value_js_' . $element['type'];
- if (function_exists($function)) {
- // @todo reverse parameter order for consistency, PieForm first
- $result .= $function($element, $this);
- }
- else {
- $result .= " data['" . $element['name'] . "'] = document.forms['$this->name'].elements['{$element['name']}'].value;\n";
- }
- }
- }
+
+ if (!empty($this->data['ajaxsuccesscallback'])) {
+ $result .= " {$this->data['ajaxsuccesscallback']}(data);\n";
}
- // Add only the submit button that was clicked
- $result .= " data[{$this->name}_btn] = document.forms['$this->name'].elements['{$this->name}_' + {$this->name}_btn].value;\n";
- // Add the hidden element for detecting form submission
- $result .= " data['pieform_{$this->name}'] = '';\n";
-
- $action = ($this->action) ? $this->action : basename($_SERVER['PHP_SELF']);
- $method = ($this->get_method() == 'get') ? 'GET' : 'POST';
$result .= <<<EOF
- var req = getXMLHttpRequest();
- req.open('{$method}', '{$action}');
- req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
- var d = sendXMLHttpRequest(req,queryString(data));
- d.addCallbacks(
- function (result) {
- {$this->name}_remove_all_errors();
- var data = evalJSONRequest(result);
- if (data.error) {
- {$this->name}_message(data.message, 'error');
- for (error in data.errors) {
- {$this->name}_set_error(data.errors[error], error);
}
+ else if (data.returnCode == 1) {
+ // The request failed validation
+ {$this->name}_message(data.message, 'error');
+ for (error in data.errors) {
+ {$this->name}_set_error(data.errors[error], error);
+ }
EOF;
- if (!empty($this->ajaxfailurefunction)) {
- $result .= " {$this->ajaxfailurefunction}(data);\n";
+ if (!empty($this->data['ajaxfailurecallback'])) {
+ $result .= " {$this->data['ajaxfailurecallback']}(data);\n";
}
$result .= <<<EOF
- }
- else {
- {$this->name}_message(data.message, 'ok');
+ }
+ else if (data.returnCode == 2) {
+ window.location = data.message;
+ }
+ else {
+ // A return code we don't know about
+ // @todo call some predefined function passing the data
+ alert('an unknown error occured (if you are a mahara dev, see Nigel)');
+ }
EOF;
-
- if (!empty($this->ajaxsuccessfunction)) {
- $result .= " {$this->ajaxsuccessfunction}(data);\n";
+ if (!empty($this->data['postajaxsubmitcallback'])) {
+ $result .= " {$this->data['postajaxsubmitcallback']}();\n";
}
- $result .= " {$this->name}_remove_all_errors();\n";
- $result .= " }\n";
- if (!empty($this->postajaxsubmitcallback)) {
- $result .= " $this->postajaxsubmitcallback();\n";
+ $result .= <<<EOF
}
+ }
- $strunknownerror = $this->i18n('ajaxunknownerror');
- $strprocessingform = $this->i18n('processingform');
- $result .= <<<EOF
- },
- function() {
- {$this->name}_message('{$strunknownerror}', 'error');
+ if ({$this->name}_btn) {
+ {$this->name}_message('{$strprocessingform}', 'info');
+ }
+});
+
EOF;
- if (!empty($this->postajaxsubmitcallback)) {
- $result .= " $this->postajaxsubmitcallback();\n";
+ $function = 'pieform_renderer_' . $this->data['renderer'] . '_messages_js';
+ if (!function_exists($function)) {
+ throw new PieformException('No renderer message function "' . $function . '"');
}
- $result .= <<<EOF
- });
- {$this->name}_message('{$strprocessingform}', 'info');
- e.stop();
-});
-EOF;
-
- $js_messages_function = 'pieform_renderer_' . $this->renderer . '_messages_js';
- if (!function_exists($js_messages_function)) {
- $this->include_plugin('renderer', $this->renderer);
- if (!function_exists($js_messages_function)) {
- throw new PieformException('No renderer message function "' . $js_messages_function . '"');
- }
+ return $result . $function($this->name);
+ }
+
+ public function json_reply($returncode, $message=null, $errors=null) {
+ $data = array(
+ 'returnCode' => intval($returncode),
+ 'message' => $message
+ );
+ if ($errors) {
+ $data['errors'] = $errors;
}
+ $result = json_encode($data);
+ log_debug($result);
- return $result . $js_messages_function($this->name);
+ echo <<<EOF
+<html><head><script type="text/javascript">function sendResult() { parent.pieformHandler_{$this->name}($result); }</script></head><body onload="sendResult(); "></body></html>
+EOF;
+ exit;
}
/**
@@ -1066,7 +878,7 @@
* @throws PieformException If the element could not be found
*/
public function set_error($name, $message) {
- foreach ($this->elements as &$element) {
+ foreach ($this->data['elements'] as &$element) {
if ($element['type'] == 'fieldset') {
foreach ($element['elements'] as &$subelement) {
if ($subelement['name'] == $name) {
@@ -1215,7 +1027,7 @@
}
// Check the configured include paths if they are specified
- foreach ($this->configdirs as $directory) {
+ foreach ($this->data['configdirs'] as $directory) {
$file = "$directory/{$type}s/$name.php";
if (is_readable($file)) {
include_once($file);
@@ -1238,17 +1050,37 @@
*
* Returns english by default.
*
- * @param string $key The language key to look up
- * @return string The internationalised string
+ * @param string $plugin The type of plugin (element, renderer, rule)
+ * @param string $pluginname The name of the plugin to get the language
+ * strings for
+ * @param string $key The language key to look up
+ * @param array $element The element to get the string for. Elements
+ * can specify there own i18n strings for rules
+ * @return string The internationalised string
*/
- public function i18n($key) {
- $function = 'pieform_' . $key . '_i18n';
- if (function_exists($function)) {
- return $function($this->language);
+ public function i18n($plugin, $pluginname, $key, $element) {
+ if (!in_array($plugin, array('element', 'renderer', 'rule'))) {
+ throw new PieformException("Invalid plugin name '$plugin'");
}
- if (isset($this->language_strings[$this->language][$key])) {
- return $this->language_strings[$this->language][$key];
+
+ // Check the element itself for the language string
+ if ($plugin == 'rule' && isset($element['rulei18n'][$key])) {
+ return $element['rulei18n'][$key];
}
+
+ // Check to see if a default was configured for the form
+ if ($plugin == 'rule' && isset($this->data['rulei18n'][$key])) {
+ return $this->data['rulei18n'][$key];
+ }
+
+ // Fall back to the default string
+ $function = 'pieform_' . $plugin . '_' . $pluginname . '_i18n';
+ if (function_exists($function)) {
+ $strings = $function();
+ return $strings[$this->data['language']][$key];
+ }
+
+ // We don't recognise this string
return '[[' . $key . ']]';
}
@@ -1277,14 +1109,16 @@
}
}
- private static function validate_js_callback($name) {
- if ($name == '') {
- return '';
+ /**
+ * Makes sure that the ajax callbacks for this form are valid javascript
+ * function names.
+ */
+ private function validate_js_callbacks() {
+ foreach (array('preajaxsubmitcallback', 'postajaxsubmitcallback', 'ajaxsuccesscallback', 'ajaxfailurecallback') as $callback) {
+ if ($this->data[$callback] != '' && !preg_match('/^[a-zA-Z][a-zA-Z0-9_]*$/', $this->data[$callback])) {
+ throw new PieformException("'{$this->data[$callback]}' is not a valid javascript callback name for callback '$callback'");
+ }
}
- if (!preg_match('/^[a-zA-Z][a-zA-Z0-9_]*$/', $name)) {
- throw new PieformException("'$name' is not a valid javascript callback name");
- }
- return $name;
}
/**
@@ -1308,7 +1142,7 @@
* an error on it
*/
private function auto_focus_first_error() {
- foreach ($this->elements as &$element) {
+ foreach ($this->data['elements'] as &$element) {
if ($element['type'] == 'fieldset') {
foreach ($element['elements'] as &$subelement) {
if (isset($subelement['error'])) {
@@ -1343,37 +1177,27 @@
* {@internal This is separate so that child element types can nest other
* elements inside them (like the fieldset element does for example).}}
*
- * @param array $element The element to render
* @param Pieform $form The form to render the element for
+ * @param array $element The element to render
* @return string The rendered element
*/
-function pieform_render_element($element, Pieform $form) {
+function pieform_render_element(Pieform $form, $element) {
// If the element is pure markup, don't pass it to the renderer
if ($element['type'] == 'markup') {
return $element['value'] . "\n";
}
// Make sure that the function to render the element type is available
- $function = 'pieform_render_' . $element['type'];
+ $function = 'pieform_element_' . $element['type'];
- // Work out the renderer function required and make sure it exists
- if ($renderer = $form->get_renderer()) {
- $rendererfunction = 'pieform_renderer_' . $renderer;
- if (!function_exists($rendererfunction)) {
- $form->include_plugin('pieform/renderers/' . $renderer . '.php');
- if (!function_exists($rendererfunction)) {
- throw new PieformException('No such form renderer: "' . $renderer . '"');
- }
- }
+ $rendererfunction = 'pieform_renderer_' . $form->get_property('renderer');
+ if (!function_exists($rendererfunction)) {
+ throw new PieformException('No such form renderer function: "' . $rendererfunction . '"');
}
- else {
- throw new PieformException('No form renderer specified for form "' . $form->get_name() . '"');
- }
$element['id'] = Pieform::make_id($element);
$element['class'] = Pieform::make_class($element);
- // @todo reverse order of parameters for consistency, a Form object first
- $builtelement = $function($element, $form);
+ $builtelement = $function($form, $element);
// Remove the 'autofocus' class, because we only want it on the form input
// itself, not the wrapping HTML
@@ -1386,7 +1210,7 @@
$htmlelements = array();
foreach ($GLOBALS['_PIEFORM_REGISTRY'] as $form) {
foreach ($form->get_elements() as $element) {
- $function = 'pieform_get_headdata_' . $element['type'];
+ $function = 'pieform_element_' . $element['type'] . '_get_headdata';
if (function_exists($function)) {
$elems = $function($element);
$htmlelements = array_merge($htmlelements, $elems);
@@ -1397,4 +1221,8 @@
return array_unique($htmlelements);
}
+define('PIEFORM_OK', 0);
+define('PIEFORM_ERR', 1);
+define('PIEFORM_CANCEL', 2);
+
?>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|