[Pieforms-commit] SF.net SVN: pieforms: [135] pieforms-php5/trunk/src/pieform.php
Status: Alpha
Brought to you by:
oracleshinoda
|
From: <ora...@us...> - 2006-12-23 13:23:23
|
Revision: 135
http://svn.sourceforge.net/pieforms/?rev=135&view=rev
Author: oracleshinoda
Date: 2006-12-23 05:23:23 -0800 (Sat, 23 Dec 2006)
Log Message:
-----------
* You can now have a javascript presubmit function non javascript forms.
* A bunch of the callbacks have had their names changed for yet more consistency.
* Forms that use a hidden iframe to submit to are now known as 'javascript forms' or 'jsforms', not AJAX forms, because they're not using AJAX. A bunch of the callbacks have been renamed based on this.
* Support has been added for a PHP callback if a form fails to validate, and a javascript callback if the returnCode is not recognised.
* Some function calls were changed to use call_user_func_array, which allows the possibility that they're not just strings (i.e. they could be class/method array pairs)
* Reduced the number of parameters for json_reply to two, now the 'errors' index of the 'message' data holds any errors specific to form elements.
* The errors sent back will now be set for any nonzero return code.
* Broke out the javascript for detecting which button was pressed last into its own method.
* Unset the detected last pressed submit button just before the form callback finishes, which prevents randomness when pressing cancel buttons later
* Made the get_errors method public, someone else may want access to it.
Modified Paths:
--------------
pieforms-php5/trunk/src/pieform.php
Modified: pieforms-php5/trunk/src/pieform.php
===================================================================
--- pieforms-php5/trunk/src/pieform.php 2006-12-23 13:13:02 UTC (rev 134)
+++ pieforms-php5/trunk/src/pieform.php 2006-12-23 13:23:23 UTC (rev 135)
@@ -73,7 +73,6 @@
// stuff much easier (form_validate_email, form_validate_date etc).
// - Collapsible js for fieldsets
// - Grippie for textareas
- // - javascript validation (probably won't be done as ajax validation is pretty good)
// - handle multipage forms?
// - handle a tabbed interface type of form?
//
@@ -188,24 +187,86 @@
// Assign defaults for the form
$formdefaults = array(
- 'method' => 'get',
- 'action' => '',
- 'elements' => array(),
- 'renderer' => 'table',
- 'ajaxform' => false,
- 'preajaxsubmitcallback' => '',
- 'postajaxsubmitcallback' => '',
- 'ajaxsuccesscallback' => '',
- 'ajaxfailurecallback' => '',
- 'validate' => true,
- 'submit' => true,
+ // The method used to submit the form, should always be 'get' or 'post'
+ 'method' => 'get',
+
+ // The form target. The vast majority of the time this should be blank,
+ // as the functions that handle the submit should be in the same script
+ // as the form definition
+ 'action' => '',
+
+ // The form elements
+ 'elements' => array(),
+
+ // The form renderer (see the pieform/renderers directory)
+ 'renderer' => 'table',
+
+ // Whether to validate the form. Non validated forms have none of the
+ // validate, success or error callbacks called on them
+ 'validate' => true,
+
+ // Whether to process the submission of this form. The form will still
+ // be validated. Handy if the code handling the submission is elsewhere
+ 'submit' => true,
+
+ // The PHP callback called to validate the form. Optional
'validatecallback' => '',
- 'submitcallback' => '',
- 'iscancellable' => true,
+
+ // The PHP callback called to process the submission of the form.
+ // Required, unless a success function is provided for each submit
+ // button in the form
+ 'successcallback' => '',
+
+ // The PHP callback called if there is any validation error. Optional
+ 'errorcallback' => '',
+
+ // Whether this form should submit to a hidden iframe and use DOM
+ // manipulation to insert error messages (faster than a normal submit,
+ // supported in less browsers. Most modern browsers should be fine)
+ 'jsform' => false,
+
+ // The javascript function called before submission of a form
+ // (regardless of whether the form is a jsform)
+ 'presubmitcallback' => '',
+
+ // The javascript function called after submission of a form. As non-js
+ // forms will trigger a page load on submit, this has no effect for them.
+ 'postsubmitcallback' => '',
+
+ // The javascript function called if the form submission was successful
+ 'jssuccesscallback' => '',
+
+ // The javascript function called if the form submission was unsuccessful
+ 'jserrorcallback' => '',
+
+ // The javascript function called if the form submission returned an
+ // unknown error code
+ 'globaljserrorcallback' => '',
+
+ // Whether this form can be cancelled, regardless of the presence of
+ // 'cancel' buttons or form inputs mischeviously named as to behave
+ // like cancel buttons
+ 'iscancellable' => true,
+
+ // Whether to auto-focus either the first field (if the value is true,
+ // or the named field (if the value is a string) when the form is
+ // displayed. If this has any value other than false and the form has
+ // been submitted with an error, the first field with an error will
+ // be focussed.
'autofocus' => false,
+
+ // The directories to search for additional elements, renderers and
+ // rules
'configdirs' => array(),
+
+ // The language to use for any form strings, such as those found in
+ // rules.
'language' => 'en.utf8',
+
+ // Any overriding language strings for rules
'rulei18n' => array(),
+
+ // The tabindex for the form (managed automatically by Pieforms)
'tabindex' => false
);
$data = array_merge($formdefaults, $formconfig, $data);
@@ -218,7 +279,7 @@
}
// Make sure that the javascript callbacks are valid
- if ($this->data['ajaxform']) {
+ if ($this->data['jsform']) {
$this->validate_js_callbacks();
}
@@ -226,8 +287,8 @@
$this->data['validatecallback'] = $this->name . '_validate';
}
- if (!$this->data['submitcallback']) {
- $this->data['submitcallback'] = $this->name . '_submit';
+ if (!$this->data['successcallback']) {
+ $this->data['successcallback'] = $this->name . '_submit';
}
$this->data['configdirs'] = array_map(
@@ -405,7 +466,7 @@
if (!isset($element['goto'])) {
throw new PieformException('Cancel element "' . $element['name'] . '" has no page to go to');
}
- if ($this->data['ajaxform']) {
+ if ($this->data['jsform']) {
$this->json_reply(PIEFORM_CANCEL, $element['goto']);
}
header('HTTP/1.1 303 See Other');
@@ -422,15 +483,15 @@
$this->validate($values);
// Then user specific validation if a function is available for that
$function = $this->data['validatecallback'];
- if (function_exists($function)) {
- $function($this, $values);
+ if (is_callable($function)) {
+ call_user_func_array($function, array($this, $values));
}
// Submit the form if things went OK
if ($this->data['submit'] && !$this->has_errors()) {
$submitted = false;
foreach ($this->get_elements() as $element) {
- if (!empty($element['submitelement']) == true && isset($global[$element['name']])) {
+ if (!empty($element['submitelement']) && isset($global[$element['name']])) {
$function = "{$this->name}_submit_{$element['name']}";
if (function_exists($function)) {
$function($this, $values);
@@ -439,13 +500,13 @@
}
}
}
- $function = $this->data['submitcallback'];
- if (!$submitted && function_exists($function)) {
+ $function = $this->data['successcallback'];
+ if (!$submitted && is_callable($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($this, $values);
+ call_user_func_array($function, array($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';
@@ -464,15 +525,21 @@
if ($this->data['autofocus'] !== false) {
$this->auto_focus_first_error();
}
+
+ // Call the user-defined PHP error function, if it exists
+ $function = $this->data['errorcallback'];
+ if (is_callable($function)) {
+ call_user_func_array($function, array($this));
+ }
- // If the form has been submitted by ajax, return ajax
- if ($this->data['ajaxform']) {
+ // If the form has been submitted by javascript, return json
+ if ($this->data['jsform']) {
$errors = $this->get_errors();
$json = array();
foreach ($errors as $element) {
$json[$element['name']] = $element['error'];
}
- $this->json_reply(PIEFORM_ERR, '@todo allow forms to specify a local error message', $json);
+ $this->json_reply(PIEFORM_ERR, array('errors' => $json));
}
}
}
@@ -580,9 +647,18 @@
$result .= "</form>\n";
}
- if ($this->data['ajaxform']) {
+ if ($this->data['jsform'] || $this->data['presubmitcallback']) {
$result .= '<script type="text/javascript">';
- $result .= "\n" . $this->submit_js();
+ $result .= "\n" . $this->whichbutton_js();
+ }
+ if ($this->data['jsform']) {
+ $result .= $this->submit_js();
+ }
+ else if ($this->data['presubmitcallback']) {
+ $result .= 'connect(\'' . $this->name . '\', \'onsubmit\', '
+ . 'function() { ' . $this->data['presubmitcallback'] . "('{$this->name}', {$this->name}_btn); });";
+ }
+ if ($this->data['jsform'] || $this->data['presubmitcallback']) {
$result .= "\n</script>\n";
}
@@ -730,9 +806,7 @@
}
}
- private function submit_js() {
- $strprocessingform = get_string('processingform');
-
+ private function whichbutton_js() {
$result = "var {$this->name}_btn = null;\n";
$connecteventadded = false;
@@ -742,20 +816,32 @@
$result .= "addLoadEvent(function() {\n";
$connecteventadded = true;
}
- $result .= " connect($('{$this->name}_{$element['name']}'), 'onclick', function() { {$this->name}_btn = '{$element['name']}'; });\n";
+ if (!empty($element['cancelelement'])) {
+ $cancelstr = 'cancel_';
+ }
+ else {
+ $cancelstr = '';
+ }
+ $result .= " connect($('{$cancelstr}{$this->name}_{$element['name']}'), 'onclick', function() { {$this->name}_btn = '{$cancelstr}{$this->name}_{$element['name']}'; });\n";
}
}
if ($connecteventadded) {
$result .= "});\n";
}
- $result .= <<<EOF
+ return $result;
+ }
+
+ private function submit_js() {
+ $strprocessingform = get_string('processingform');
+
+ $result = <<<EOF
connect($('{$this->name}'), 'onsubmit', function(e) {
if (typeof(tinyMCE) != 'undefined') { tinyMCE.triggerSave(); }
EOF;
- if (!empty($this->data['preajaxsubmitcallback'])) {
- $result .= " {$this->data['preajaxsubmitcallback']}();\n";
+ if (!empty($this->data['presubmitcallback'])) {
+ $result .= " {$this->data['presubmitcallback']}('{$this->name}', {$this->name}_btn);\n";
}
$result .= <<<EOF
@@ -770,60 +856,78 @@
insertSiblingNodesAfter($('{$this->name}'), iframe);
window.pieformHandler_{$this->name} = function(data) {
- {$this->name}_remove_all_errors();
+
+EOF;
+ if (isset($this->data['processingstopcallback'])) {
+ $result .= " {$this->data['processingstopcallback']}('{$this->name}', {$this->name}_btn);\n";
+ }
+
+ $result .= <<<EOF
evalJSONRequest(data);
if (data.returnCode == 0) {
+ {$this->name}_remove_all_errors();
// The request completed successfully
- {$this->name}_message(data.message, 'ok');
EOF;
-
- if (!empty($this->data['ajaxsuccesscallback'])) {
- $result .= " {$this->data['ajaxsuccesscallback']}(data);\n";
+ if (!empty($this->data['jssuccesscallback'])) {
+ $result .= " {$this->data['jssuccesscallback']}('{$this->name}', data);\n";
}
-
$result .= <<<EOF
}
- 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);
+ else {
+ // Redirect if the form is being cancelled
+ if (data.returnCode == 2) {
+ window.location = data.message;
+ return;
}
+
+ // Set errors if there are any
+ {$this->name}_remove_all_errors();
+ if (data.message.errors) {
+ for (error in data.message.errors) {
+ {$this->name}_set_error(data.message.errors[error], error);
+ }
+ }
+ if (data.returnCode == 1) {
+ // The request failed validation
+
EOF;
- if (!empty($this->data['ajaxfailurecallback'])) {
- $result .= " {$this->data['ajaxfailurecallback']}(data);\n";
+ // @todo: renumber the PIEFORM_* flags to be 0, -1, -2 to allow users to have the positive numbers to themselves
+ if (!empty($this->data['jserrorcallback'])) {
+ $result .= " {$this->data['jserrorcallback']}('{$this->name}', data);\n";
}
$result .= <<<EOF
+ }
+ else {
+ // A return code we don't know about
+
+EOF;
+ if (!empty($this->data['globaljserrorcallback'])) {
+ $result .= " {$this->data['globaljserrorcallback']}('{$this->name}', data);\n";
+ }
+ else {
+ $result .= " alert('Developer: got error code ' + data.returnCode
+ + ', either fix your form to not use this code or define a global js error handler');\n";
+ }
+ $result .= <<<EOF
+ }
}
- 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->data['postajaxsubmitcallback'])) {
- $result .= " {$this->data['postajaxsubmitcallback']}();\n";
+ if (!empty($this->data['postsubmitcallback'])) {
+ $result .= " {$this->data['postsubmitcallback']}('{$this->name}', {$this->name}_btn);\n";
}
$result .= <<<EOF
+ {$this->name}_btn = null;
}
}
- if ({$this->name}_btn) {
- {$this->name}_message('{$strprocessingform}', 'info');
- }
-});
-
-
EOF;
+ $result .= "});\n\n";
$function = 'pieform_renderer_' . $this->data['renderer'] . '_messages_js';
if (!function_exists($function)) {
throw new PieformException('No renderer message function "' . $function . '"');
@@ -832,14 +936,11 @@
return $result . $function($this->name);
}
- public function json_reply($returncode, $message=null, $errors=null) {
+ public function json_reply($returncode, $message=null) {
$data = array(
'returnCode' => intval($returncode),
'message' => $message
);
- if ($errors) {
- $data['errors'] = $errors;
- }
$result = json_encode($data);
echo <<<EOF
@@ -1117,11 +1218,12 @@
}
/**
- * Makes sure that the ajax callbacks for this form are valid javascript
+ * Makes sure that the javascript callbacks for this form are valid javascript
* function names.
*/
private function validate_js_callbacks() {
- foreach (array('preajaxsubmitcallback', 'postajaxsubmitcallback', 'ajaxsuccesscallback', 'ajaxfailurecallback') as $callback) {
+ foreach (array('presubmitcallback', 'postsubmitcallback', 'jssuccesscallback',
+ 'jserrorcallback', 'globaljserrorcallback') 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'");
}
@@ -1134,7 +1236,7 @@
* @return array An array of elements with errors on them, the empty array
* in the result of no errors.
*/
- private function get_errors() {
+ public function get_errors() {
$result = array();
foreach ($this->get_elements() as $element) {
if (isset($element['error'])) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|