[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. |