From c81e8f1197f083ed0a42c65c95302959b29ac700 Mon Sep 17 00:00:00 2001 From: DarkSide Date: Fri, 24 Feb 2017 14:40:49 +0200 Subject: [PATCH 01/23] * a lot of comments for View methods * new method View->removeAttr() * renderView() will use app->encodeAttribute() for easier reusability of this method --- src/App.php | 15 ++++++++ src/Template.php | 8 ++++ src/View.php | 99 +++++++++++++++++++++++++++++++++++------------- 3 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/App.php b/src/App.php index e7c4dfae9b..5ef5291ab2 100644 --- a/src/App.php +++ b/src/App.php @@ -14,6 +14,7 @@ class App public $template_dir = null; + // @var string Name of skin public $skin = 'semantic-ui'; /** @@ -301,11 +302,25 @@ public function getTag($tag = null, $attr = null, $value = null) return "<$tag".($tmp ? (' '.implode(' ', $tmp)) : '').$postfix.'>'.($value ? $value."" : ''); } + /** + * Encodes string - removes HTML special chars. + * + * @param string $val + * + * @return string + */ public function encodeAttribute($val) { return htmlspecialchars($val); } + /** + * Encodes string - removes HTML entities. + * + * @param string $val + * + * @return string + */ public function encodeHTML($val) { return htmlentities($val); diff --git a/src/Template.php b/src/Template.php index 33560cae18..6e56202c2f 100644 --- a/src/Template.php +++ b/src/Template.php @@ -614,6 +614,10 @@ protected function parseTemplate($str) /** * Render either a whole template or a specified region. Returns * current contents of a template. + * + * @param string $region + * + * @return string */ public function render($region = null) { @@ -627,6 +631,10 @@ public function render($region = null) /** * Walk through the template array collecting the values * and returning them as a string. + * + * @param array $template + * + * @return string */ protected function recursiveRender(&$template) { diff --git a/src/View.php b/src/View.php index 4cd20c98e0..6eaefeddd1 100644 --- a/src/View.php +++ b/src/View.php @@ -52,11 +52,15 @@ class View implements jsExpressionable * Enables UI keyword for Semantic UI indicating that this is a * UI element. If you set this variable value to string, it will * be appended at the end of the element class. + * + * @var bool */ public $ui = false; /** * ID of the element, that's unique and is used in JS operations. + * + * @var string */ public $id = null; @@ -83,6 +87,8 @@ class View implements jsExpressionable /** * Just here temporarily, until App picks it up. + * + * @var string */ protected $skin; @@ -108,14 +114,19 @@ class View implements jsExpressionable /** * Set static contents of this view. + * + * @var string|false */ public $content = null; /** * Change this if you want to substitute default "div" for something else. + * + * @var string */ public $element = null; + // @var array protected $_add_later = []; // }}} @@ -126,7 +137,7 @@ class View implements jsExpressionable * May accept properties of a class, but if property is not defined, it will * be used as a HTML class instead. * - * @param array $defaults + * @param array|string $defaults * * @throws Exception */ @@ -195,11 +206,11 @@ public function setSource(array $data) } /** - * Called from __construct() and set() to initialize teh properties. + * Called from __construct() and set() to initialize the properties. * * TODO: move into trait, because this is used often * - * @param $properties + * @param array $properties */ protected function setProperties($properties) { @@ -211,7 +222,7 @@ protected function setProperties($properties) if (property_exists($this, $key)) { if (is_array($val)) { $this->$key = array_merge(isset($this->$key) && is_array($this->$key) ? $this->$key : [], $val); - } elseif (!is_null($val)) { + } elseif ($val !== null) { $this->$key = $val; } } else { @@ -247,8 +258,8 @@ protected function setProperty($key, $val) throw new Exception([ 'Not sure what to do', - 'key'=> $key, - 'val'=> $val, + 'key' => $key, + 'val' => $val, ]); } @@ -262,6 +273,7 @@ protected function setProperty($key, $val) */ public function init() { + // set name and id of view if (!$this->name) { if (!$this->id) { $this->id = $this->name = 'atk'; @@ -272,16 +284,19 @@ public function init() $this->id = $this->name; } + // initialize $this->_init(); if (!$this->app) { $this->initDefaultApp(); } + // set up template if (is_string($this->defaultTemplate) && is_null($this->template)) { $this->template = $this->app->loadTemplate($this->defaultTemplate); } + // add default objects foreach ($this->_add_later as list($object, $region)) { $this->add($object, $region); } @@ -307,6 +322,8 @@ protected function initDefaultApp() * @param string|array $region (or array for full set of defaults) * * @return View + * + * @throws Exception */ public function add($object, $region = null) { @@ -314,7 +331,7 @@ public function add($object, $region = null) if (!$this->app) { $this->init(); } - */ + */ if (!$this->app) { $this->_add_later[] = [$object, $region]; @@ -372,16 +389,15 @@ public function add($object, $region = null) */ public function set($arg1 = [], $arg2 = null) { - if (is_string($arg1) && !is_null($arg2)) { + if (is_string($arg1) && $arg2 !== null) { // must be initialized - $this->template->set($arg1, $arg2); return $this; } - if (!is_null($arg2)) { + if ($arg2 !== null) { throw new Exception([ 'Second argument to set() can be only passed if the first one is a string', 'arg1'=> $arg1, @@ -454,10 +470,12 @@ public function removeClass($class) * @param string $style CSS Style definition * * @return $this + * + * @todo Think about difference between setStyle and addStyle */ public function setStyle($property, $style = null) { - if (is_array($property) && is_null($style)) { + if (is_array($property) && $style === null) { foreach ($property as $k => $v) { $this->addStyle($k, $v); } @@ -495,8 +513,8 @@ public function removeStyle($property) /** * Set attribute. * - * @param string|array $attr - * @param string $value + * @param string|array $attr Attribute name or hash + * @param string $value Attribute value * * @return $this */ @@ -513,13 +531,35 @@ public function setAttr($attr, $value = null) return $this; } + /** + * Remove attribute. + * + * @param string|array $attr Attribute name or hash + * + * @return $this + */ + public function removeAttr($property) + { + if (is_array($property)) { + foreach ($property as $v) { + unset($this->attr[$v]); + } + + return $this; + } + + unset($this->attr[$property]); + + return $this; + } + // }}} // {{{ Rendering /** * View-specific rendering stuff. Feel free to replace this method with - * your own. View::renderView contanis some logic that integrates with + * your own. View::renderView contains some logic that integrates with * semanticUI. * * NOTE: maybe in the future, SemanticUI-related stuff needs to go into @@ -561,7 +601,7 @@ function (&$item, $key) { if ($this->attr) { $tmp = []; foreach ($this->attr as $attr => $val) { - $tmp[] = $attr.'="'.htmlspecialchars($val).'"'; + $tmp[] = $attr.'="'.$this->app->encodeAttribute($val).'"'; } $this->template->set('attributes', implode(' ', $tmp)); } @@ -574,12 +614,6 @@ function (&$item, $key) { public function recursiveRender() { foreach ($this->elements as $view) { - if ($this->app && $view instanceof \atk4\core\AppScopeTrait && !$view->app) { - $view->app = $this->app; - $view->name = $this->name.$view->short_name; - $view->init(); - } - if (!$view instanceof self) { continue; } @@ -614,6 +648,8 @@ public function renderAll() /** * This method is for those cases when developer want to simply render his * view and grab HTML himself. + * + * @return string */ public function render() { @@ -625,7 +661,10 @@ public function render() } /** - * Created for recursive rendering or when you want to only get HTML of this object (not javascript). + * Created for recursive rendering or when you want to only get HTML of + * this object (not javascript). + * + * @return string */ public function getHTML() { @@ -681,11 +720,12 @@ public function getHTML() * * @link http://agile-ui.readthedocs.io/en/latest/js.html * - * @param string|bool|null $when Event when chain will be executed + * @param string|bool|null $when Event when chain will be executed + * @param jsExpression $action JavaScript action * * @return jQuery */ - public function js($when = null, $extra = null) + public function js($when = null, $action = null) { $chain = new jQuery($this); @@ -704,8 +744,8 @@ public function js($when = null, $extra = null) $this->_js_actions[$when][] = $chain; - if ($extra) { - $this->_js_actions[$when][] = $extra; + if ($action) { + $this->_js_actions[$when][] = $action; } return $chain; @@ -875,6 +915,13 @@ function ($app) use ($event, $selector, $ret_js, $on_chain, &$fired) { */ } + /** + * Render this view into #id for javascript. + * + * @return string + * + * @throws Exception + */ public function jsRender() { if (!$this->_initialized) { From a26cb7559f398aaabd45092fdd0d973736f4d3ee Mon Sep 17 00:00:00 2001 From: DarkSide Date: Fri, 24 Feb 2017 14:42:36 +0200 Subject: [PATCH 02/23] nothing much --- src/App.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/App.php b/src/App.php index 5ef5291ab2..addee06945 100644 --- a/src/App.php +++ b/src/App.php @@ -8,6 +8,7 @@ class App init as _init; } + // @var string Name of application public $title = 'Agile UI - Untitled Application'; public $layout = null; // the top-most view object From 9fa657ad62d066a2a3e9055b7586682483342f7a Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Fri, 24 Feb 2017 12:44:34 +0000 Subject: [PATCH 03/23] Apply fixes from StyleCI --- src/View.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/View.php b/src/View.php index 6eaefeddd1..a21aa5f46f 100644 --- a/src/View.php +++ b/src/View.php @@ -321,9 +321,9 @@ protected function initDefaultApp() * @param View|string $object New object to add * @param string|array $region (or array for full set of defaults) * - * @return View - * * @throws Exception + * + * @return View */ public function add($object, $region = null) { @@ -918,9 +918,9 @@ function ($app) use ($event, $selector, $ret_js, $on_chain, &$fired) { /** * Render this view into #id for javascript. * - * @return string - * * @throws Exception + * + * @return string */ public function jsRender() { From cdcce613c74d666be282cf8f208fd26a367b1a41 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Fri, 24 Feb 2017 17:02:24 +0200 Subject: [PATCH 04/23] Prevent exit from triggering when sending JSON output. #48 --- .gitignore | 2 ++ src/App.php | 9 +++++---- src/jsCallback.php | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 005e299656..b3273202b1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ docs/build /build .DS_Store *.codekit3 + +run_local.sh diff --git a/src/App.php b/src/App.php index e7c4dfae9b..ed1e015fe9 100644 --- a/src/App.php +++ b/src/App.php @@ -26,7 +26,7 @@ class App */ public $always_run = true; - private $run_called = false; + public $run_called = false; public $ui_persistence = null; @@ -58,12 +58,13 @@ public function __construct($defaults = []) }); } + if (!$this->_initialized) { + $this->init(); + } + // Always run app on shutdown if ($this->always_run) { register_shutdown_function(function () { - if (!$this->_initialized) { - $this->init(); - } if (!$this->run_called) { try { diff --git a/src/jsCallback.php b/src/jsCallback.php index fda1e53c52..c89073cb1f 100644 --- a/src/jsCallback.php +++ b/src/jsCallback.php @@ -54,6 +54,7 @@ public function set($callback, $args = []) }, $actions)); echo json_encode(['success'=>true, 'message'=>'Hello World', 'eval'=>$ajaxec]); + $this->app->run_called = true; // prevent shutdown function from triggering. exit; }); } From 456a8f3e8b2e85233a4992488c5a220753688831 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Fri, 24 Feb 2017 17:02:45 +0200 Subject: [PATCH 05/23] Fixes #48 and #47 --- src/View.php | 113 +++++++-------------------------------------------- 1 file changed, 15 insertions(+), 98 deletions(-) diff --git a/src/View.php b/src/View.php index 4cd20c98e0..82633ee9b2 100644 --- a/src/View.php +++ b/src/View.php @@ -691,22 +691,23 @@ public function js($when = null, $extra = null) // Substitute $when to make it better work as a array key if ($when === true) { - $when = 'always'; - } + $this->_js_actions[$when][] = $chain; - if ($when === false || $when === null) { + if ($extra) { + $this->_js_actions[$when][] = $extra; + } return $chain; } - if (!isset($this->_js_actions[$when])) { - $this->_js_actions[$when] = []; + if ($when === false || $when === null) { + return $chain; } - $this->_js_actions[$when][] = $chain; + // next - binding on a specific event + $action = (new jQuery($this)) + ->bind($when, new jsFunction([$chain, $extra, 'preventDefault'=>true, 'stopPropagation'=>true])); - if ($extra) { - $this->_js_actions[$when][] = $extra; - } + $this->_js_actions[$when][] = $action; return $chain; } @@ -773,67 +774,11 @@ public function on($event, $selector = null, $action = null, $defaults = null) $cb->set(function () use ($action) { $chain = new jQuery(new jsExpression('this')); - $response = call_user_func($action, $chain); - - if ($response === $chain) { - $response = null; - } - - $actions = []; - - if ($chain->_chain) { - $actions[] = $chain; - } - - if (!is_array($response)) { - $response = [$response]; - } - - foreach ($response as $r) { - if (is_string($r)) { - $actions[] = new jsExpression('alert([])', [r]); - } elseif ($r instanceof jsExpressionable) { - $actions[] = $r; - } elseif ($r === null) { - continue; - } else { - throw new Exception(['Incorrect callback. Must be string or action.', 'r'=>$r]); - } - } - - $ajaxec = implode(";\n", array_map(function (jQuery $r) { - return $r->jsRender(); - }, $actions)); - - echo json_encode(['success'=>true, 'message'=>'Hello World', 'eval'=>$ajaxec]); - exit; + return call_user_func($action, $chain); }); $thisAction->api(['on'=>'now', 'url'=>$cb->getURL(), 'obj'=>new jsExpression('this')]); - //throw new Exception('VirtualPage is not yet implemented'); - /*$url = '.virtualpage->getURL..'; - $actions[] = (new jsUniv(new jsExpression('this')))->ajaxec($url, true); - - /* - $p = $this->add('VirtualPage'); - - $p->set(function ($p) use ($action) { - // $action is an actual callable - $js2 = $p->js()->_selectorRegion(); - - $js3 = call_user_func($action, $js2, $_POST); - - // If method returns something, execute that instead - if ($js3) { - $p->js(null, $js3)->execute(); - } else { - $js2->execute(); - } - }); - - $action = $this->js()->_selectorThis()->univ()->ajaxec($p->getURL(), true); - */ } elseif ($action) { // otherwise include $actions[] = $action; @@ -848,33 +793,11 @@ public function on($event, $selector = null, $action = null, $defaults = null) } return $thisAction; - - /* - if ($js) { - $ret_js = $this->js(null, $js)->_selectorThis(); - } else { - $ret_js = $this->js()->_selectorThis(); - } - - $on_chain = $this->js(true); - $fired = false; - - $this->app->jui->addHook( - 'pre-getJS', - function ($app) use ($event, $selector, $ret_js, $on_chain, &$fired) { - if ($fired) { - return; - } - $fired = true; - - $on_chain->on($event, $selector, $ret_js->_enclose(null, true)); - } - ); - - return $ret_js; - */ } + /** + * Convert View into a value in case it happens to be inside our json_encode (as argument to jsChain) + */ public function jsRender() { if (!$this->_initialized) { @@ -885,7 +808,7 @@ public function jsRender() } /** - * TODO: refactor. + * Get JavaScript objects from this render tree */ public function getJS() { @@ -893,12 +816,6 @@ public function getJS() foreach ($this->_js_actions as $event=>$eventActions) { foreach ($eventActions as $action) { - // wrap into callback - if ($event !== 'always') { - $action = (new jQuery(@$action->_constructorArgs[0])) - ->bind($event, new jsFunction([$action, 'preventDefault'=>true, 'stopPropagation'=>true])); - } - $actions[] = $action; } } From 6f68ab246783411b95d3cffffb05c8e8d880d086 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Fri, 24 Feb 2017 17:03:03 +0200 Subject: [PATCH 06/23] Clean up and add more tests for #48 --- demos/button2.php | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/demos/button2.php b/demos/button2.php index d6b25a6c17..3d07c858eb 100644 --- a/demos/button2.php +++ b/demos/button2.php @@ -6,29 +6,33 @@ use \atk4\ui\Button; use \atk4\ui\Buttons; -use \atk4\ui\H2; +use \atk4\ui\Header; -$layout->js(true, new \atk4\ui\jsExpression('$.fn.api.settings.successTest = function(response) { - if(response && response.eval) { - var result = function(){ eval(response.eval); }.call(this.obj); - } - return false; -}')); - -$layout->add(new H2('Basic Button')); +$layout->add(new Header('Basic Button')); // This button hides on page load -$b = $layout->add(new Button(['id'=>'b1']))->set('Hidden Button'); +$b = $layout->add(new Button('Hidden Button')); $b->js(true)->hide(); // This button hides when clicked $b = $layout->add(new Button(['id'=>'b2']))->set('Hide on click Button'); $b->js('click')->hide(); -$layout->add(new H2('Callbacks')); +$layout->add(new Header('Callbacks')); + +$b = $layout->add(new Button('Hide button B')); +$b2 = $layout->add(new Button('B')); +$b->js('click', $b2->js()->hide('b2'))->hide('b1'); + +$layout->add(new Header('js() method')); // On button click reload it and change it's title -$b = $layout->add(new Button(['id'=>'b3']))->set('Callback Test'); +$b = $layout->add(new Button('Callback Test')); $b->on('click', function ($b) { return $b->text(rand(1, 20)); }); + +$b = $layout->add(new Button('success')); +$b->on('click', function ($b) { + return 'success'; +}); From 6d5c8ab6d91dab7e298efa6f61a8c40d046e5457 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Fri, 24 Feb 2017 17:05:12 +0200 Subject: [PATCH 07/23] Fix form submissions #45 --- template/semantic-ui/html.html | 13 +++++++++++-- template/semantic-ui/html.jade | 13 +++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/template/semantic-ui/html.html b/template/semantic-ui/html.html index 647f1a901a..98d77c1ff8 100644 --- a/template/semantic-ui/html.html +++ b/template/semantic-ui/html.html @@ -5,13 +5,22 @@ + {$HEAD} diff --git a/template/semantic-ui/html.jade b/template/semantic-ui/html.jade index 8df407854a..32bd6e6d32 100644 --- a/template/semantic-ui/html.jade +++ b/template/semantic-ui/html.jade @@ -6,13 +6,22 @@ html(lang="{lang}en{/}") meta(charset='utf-8') link(rel='stylesheet', type='text/css', href='http://semantic-ui.com/dist/semantic.css') script(src='https://code.jquery.com/jquery-3.1.1.js') + script(src='https://cdnjs.cloudflare.com/ajax/libs/jquery-serialize-object/2.5.0/jquery.serialize-object.min.js') script(src='http://semantic-ui.com/dist/semantic.js') script. $.fn.api.settings.successTest = function(response) { if(response && response.eval) { - var result = function(){ eval(response.eval); }.call(this.obj); + try { + var result = function(){ eval(response.eval); }.call(this.obj); + } catch (e) { + //alert(e); + } } - return false; + return true; + } + + $.fn.api.settings.onFailure = function(response) { + alert(response); } | {$HEAD} style(type='text/css'). From a761002493ebc5a4103b29dfcead7f7bc9487571 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Fri, 24 Feb 2017 15:05:36 +0000 Subject: [PATCH 08/23] Apply fixes from StyleCI --- src/App.php | 1 - src/View.php | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/App.php b/src/App.php index ed1e015fe9..3e49a18ad8 100644 --- a/src/App.php +++ b/src/App.php @@ -65,7 +65,6 @@ public function __construct($defaults = []) // Always run app on shutdown if ($this->always_run) { register_shutdown_function(function () { - if (!$this->run_called) { try { $this->run(); diff --git a/src/View.php b/src/View.php index 82633ee9b2..bb2e1c3f56 100644 --- a/src/View.php +++ b/src/View.php @@ -696,6 +696,7 @@ public function js($when = null, $extra = null) if ($extra) { $this->_js_actions[$when][] = $extra; } + return $chain; } @@ -774,11 +775,11 @@ public function on($event, $selector = null, $action = null, $defaults = null) $cb->set(function () use ($action) { $chain = new jQuery(new jsExpression('this')); + return call_user_func($action, $chain); }); $thisAction->api(['on'=>'now', 'url'=>$cb->getURL(), 'obj'=>new jsExpression('this')]); - } elseif ($action) { // otherwise include $actions[] = $action; @@ -796,7 +797,7 @@ public function on($event, $selector = null, $action = null, $defaults = null) } /** - * Convert View into a value in case it happens to be inside our json_encode (as argument to jsChain) + * Convert View into a value in case it happens to be inside our json_encode (as argument to jsChain). */ public function jsRender() { @@ -808,7 +809,7 @@ public function jsRender() } /** - * Get JavaScript objects from this render tree + * Get JavaScript objects from this render tree. */ public function getJS() { From 9c25458bcb5e98d35925694d6cb7f56f9672fad5 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 00:32:19 +0200 Subject: [PATCH 09/23] Cleanup readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 05abf6a093..fe1442f329 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,14 @@ Agile UI comes with many built-in components; | [Header](http://ui.agiletoolkit.org/demos/header.php) | Simple view for header. | 0.3 | | [Menu](http://ui.agiletoolkit.org/demos/layout2.php) | Horizontal and vertical multi-dimensional menus with icons. | 0.4 | | [Form](http://ui.agiletoolkit.org/demos/form.php) | Validation, Interactivity, Feedback, Layouts, Field types. | 0.4 | -| Layouts 1 | Admin, Centered. | 0.4 | -| [Grid](http://ui.agiletoolkit.org/demos/grid.php) | Formatting, Columns, Status, Link, Template, Delete. | 0.5 | +| [Layouts 1](http://ui.agiletoolkit.org/demos/layouts.php) | Admin, Centered. | 0.4 | +| [Grid](http://ui.agiletoolkit.org/demos/grid.php) | Formatting, Columns, Status, Link, Template, Delete. | 1.0 | | GridAdvanced | Toolbar, Paginator, Quick-search, Expander, Actions. | 1.1 * | +| Messages | Such as "Info", "Error", "Warning" or "Tip" for easy use. | 1.1 * | | Dialog | Modal dialog with dynamically loaded content. | 1.1 * | | Relading | Dynamically re-render part of the UI. | 1.1 * | | Actions | Extended buttons with various interactions | 1.1 * | | CRUD | Create, List, Edit and Delete records (based on Advanced Grid) | 1.2 * | -| Messages | Such as "Info", "Error", "Warning" or "Tip" for easy use. | 1.0 | | Layouts 2 | 4 Responsive: Admin, Centered, Site, Wide. | 1.2 * | | Breadcrumb | Push links to pages for navigation. Wizard. | 1.3 * | | Items, Cards | Responsive Items and Card implementaiton. | 1.4 * | From b8bd265e7bf9a59a7373d21af73fcac5a52dcb27 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 12:39:26 +0200 Subject: [PATCH 10/23] create function for storing form data into model properly. --- src/Persistence/UI.php | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Persistence/UI.php b/src/Persistence/UI.php index 367412a95a..e27d203a19 100644 --- a/src/Persistence/UI.php +++ b/src/Persistence/UI.php @@ -64,6 +64,49 @@ public function _typecastSaveField(\atk4\data\Field $f, $value) return $v; } + /** + * Interpret user-defined input for various types + */ + public function _typecastLoadField(\atk4\data\Field $f, $value) + { + switch ($f->type) { + case 'boolean': + $value = (boolean)$value; + break; + case 'money': + return str_replace(',','', $value); + case 'date': + case 'datetime': + case 'time': + $dt_class = isset($f->dateTimeClass) ? $f->dateTimeClass : 'DateTime'; + $tz_class = isset($f->dateTimeZoneClass) ? $f->dateTimeZoneClass : 'DateTimeZone'; + + // ! symbol in date format is essential here to remove time part of DateTime - don't remove, this is not a bug + $format = ['date' => $this->date_format, 'datetime' => $this->datetime_format, 'time' => $this->time_format]; + $format = $f->persist_format ?: $format[$f->type]; + + // datetime only - set from persisting timezone + if ($f->type == 'datetime' && isset($f->persist_timezone)) { + $v = $dt_class::createFromFormat($format, $value, new $tz_class($f->persist_timezone)); + if ($v === false) { + throw new Exception(['Incorrectly formatted datetime', 'format' => $format, 'value' => $value, 'field' => $f]); + } + $v->setTimeZone(new $tz_class(date_default_timezone_get())); + return $v; + } else { + $v = $dt_class::createFromFormat($format, $value); + if ($v === false) { + throw new Exception(['Incorrectly formatted date/time', 'format' => $format, 'value' => $value, 'field' => $f]); + } + return $v; + } + + break; + } + + return $value; + } + /** * This is override of the default Persistence logic to tweak the behaviour:. * From a649c1f7cec45b0342b497e2b7ec398c466470b7 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 12:39:38 +0200 Subject: [PATCH 11/23] add links to demo sources. --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index fe1442f329..bb0c4b8330 100644 --- a/README.md +++ b/README.md @@ -28,17 +28,17 @@ Agile UI comes with many built-in components; | Name | Description | Introduced | | ---------------------------------------- | ---------------------------------------- | ---------- | -| Core | Template, Render Tree and various patterns | 0.1 | -| [Button](http://ui.agiletoolkit.org/demos/button.php) | Button in various variations including icons, labels, styles and tags | 0.1 | -| [Input](http://ui.agiletoolkit.org/demos/field.php) | Decoration of input fields, integration with buttons. | 0.2 | -| [JS](http://ui.agiletoolkit.org/demos/button2.php) | Assign JS events and abstraction of PHP callbacks. | 0.2 | -| [Header](http://ui.agiletoolkit.org/demos/header.php) | Simple view for header. | 0.3 | -| [Menu](http://ui.agiletoolkit.org/demos/layout2.php) | Horizontal and vertical multi-dimensional menus with icons. | 0.4 | -| [Form](http://ui.agiletoolkit.org/demos/form.php) | Validation, Interactivity, Feedback, Layouts, Field types. | 0.4 | -| [Layouts 1](http://ui.agiletoolkit.org/demos/layouts.php) | Admin, Centered. | 0.4 | -| [Grid](http://ui.agiletoolkit.org/demos/grid.php) | Formatting, Columns, Status, Link, Template, Delete. | 1.0 | +| Core | Template, Render Tree and various patterns | 0.1 | +| [Button](http://ui.agiletoolkit.org/demos/button.php) [[source](https://github.com/atk4/ui/blob/develop/demos/button.php#L14)] | Button in various variations including icons, labels, styles and tags | 0.1 | +| [Input](http://ui.agiletoolkit.org/demos/field.php) [[source](https://github.com/atk4/ui/blob/develop/demos/field.php#L9)] | Decoration of input fields, integration with buttons. | 0.2 | +| [JS](http://ui.agiletoolkit.org/demos/button2.php) [[source](https://github.com/atk4/ui/blob/develop/demos/button2.php#L15)] | Assign JS events and abstraction of PHP callbacks. | 0.2 | +| [Header](http://ui.agiletoolkit.org/demos/header.php) [[source](https://github.com/atk4/ui/blob/develop/demos/header.php#L8)] | Simple view for header. | 0.3 | +| [Menu](http://ui.agiletoolkit.org/demos/layout2.php) [[source](https://github.com/atk4/ui/blob/develop/demos/layout2.php#L16)] | Horizontal and vertical multi-dimensional menus with icons. | 0.4 | +| [Form](http://ui.agiletoolkit.org/demos/form.php) [[source](https://github.com/atk4/ui/blob/develop/demos/form.php#L44)] | Validation, Interactivity, Feedback, Layouts, Field types. | 0.4 | +| [Layouts](http://ui.agiletoolkit.org/demos/layouts.php) [[source](https://github.com/atk4/ui/blob/develop/demos/layout.php#L9)] | Admin, Centered. | 0.4 | +| [Grid](http://ui.agiletoolkit.org/demos/grid.php) [[source](https://github.com/atk4/ui/blob/develop/demos/grid.php#L9)] | Formatting, Columns, Status, Link, Template, Delete. | 1.0 | | GridAdvanced | Toolbar, Paginator, Quick-search, Expander, Actions. | 1.1 * | -| Messages | Such as "Info", "Error", "Warning" or "Tip" for easy use. | 1.1 * | +| Messages | Such as "Info", "Error", "Warning" or "Tip" for easy use. | 1.1 * | | Dialog | Modal dialog with dynamically loaded content. | 1.1 * | | Relading | Dynamically re-render part of the UI. | 1.1 * | | Actions | Extended buttons with various interactions | 1.1 * | From 75b310dd7c592c896b92ed1bac085da0e8074de4 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 12:39:56 +0200 Subject: [PATCH 12/23] when unexpected JSON is received - display error window. --- template/semantic-ui/html.html | 9 ++++++++- template/semantic-ui/html.jade | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/template/semantic-ui/html.html b/template/semantic-ui/html.html index 98d77c1ff8..5a8d81e8f1 100644 --- a/template/semantic-ui/html.html +++ b/template/semantic-ui/html.html @@ -20,7 +20,14 @@ } $.fn.api.settings.onFailure = function(response) { - alert(response); + w=window.open(null,'Error in JSON response','height=1000,width=1100,location=no,menubar=no,scrollbars=yes,status=no,titlebar=no,toolbar=no'); + if(w){ + w.document.write('
Error in JSON response
'); + w.document.write(response); + w.document.write('
'); + }else{ + alert("Error in ajaxec response"+response); + } } {$HEAD} diff --git a/template/semantic-ui/html.jade b/template/semantic-ui/html.jade index 32bd6e6d32..8eed30e1dc 100644 --- a/template/semantic-ui/html.jade +++ b/template/semantic-ui/html.jade @@ -21,7 +21,14 @@ html(lang="{lang}en{/}") } $.fn.api.settings.onFailure = function(response) { - alert(response); + w=window.open(null,'Error in JSON response','height=1000,width=1100,location=no,menubar=no,scrollbars=yes,status=no,titlebar=no,toolbar=no'); + if(w){ + w.document.write('
Error in JSON response
'); + w.document.write(response); + w.document.write('
'); + }else{ + alert("Error in ajaxec response"+response); + } } | {$HEAD} style(type='text/css'). From b9a01749b4837f39c14035720417061d5c5dcfeb Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:48:03 +0200 Subject: [PATCH 13/23] Demos - fix order of columns. --- demos/grid.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demos/grid.php b/demos/grid.php index 9b9ec744b4..b509a69aea 100644 --- a/demos/grid.php +++ b/demos/grid.php @@ -10,7 +10,8 @@ $bb->on('click', $g->js()->reload()); -$g->setModel(new SomeData()); +$g->setModel(new SomeData(), false); + $g->addColumn('name', new \atk4\ui\Column\Link(['details', 'id'=>'{$id}'])); $g->addColumn('surname', new \atk4\ui\Column\Template('{$surname}')); $g->addColumn('title', new \atk4\ui\Column\Status([ From 62bf90bcb345ff9deff4f6a59285ad90105e9397 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:48:22 +0200 Subject: [PATCH 14/23] include somedata def even when without layout. --- demos/init.php | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/demos/init.php b/demos/init.php index 04fecce7fa..836c6e237a 100644 --- a/demos/init.php +++ b/demos/init.php @@ -8,34 +8,35 @@ $layout = $app->layout; -if (!isset($layout->leftMenu)) { - return; -} +if (isset($layout->leftMenu)) { + + $layout->leftMenu->addItem(['Welcome Page', 'icon'=>'gift'], ['index']); + $layout->leftMenu->addItem(['Layouts', 'icon'=>'object group'], ['layouts']); -$layout->leftMenu->addItem(['Welcome Page', 'icon'=>'gift'], ['index']); -$layout->leftMenu->addItem(['Layouts', 'icon'=>'object group'], ['layouts']); + $form = $layout->leftMenu->addGroup(['Form', 'icon'=>'edit']); + $form->addItem('Basics and Layouting', ['form']); + $form->addItem('Input Field Decoration', ['field']); + $form->addItem('Data Integration', ['form2']); -$form = $layout->leftMenu->addGroup(['Form', 'icon'=>'edit']); -$form->addItem('Basics and Layouting', ['form']); -$form->addItem('Input Field Decoration', ['field']); -$form->addItem('Data Integration', ['form2']); + $form = $layout->leftMenu->addGroup(['Grid', 'icon'=>'table']); + $form->addItem('Column Formats and Features', ['grid']); -$form = $layout->leftMenu->addGroup(['Grid', 'icon'=>'table']); -$form->addItem('Column Formats and Features', ['grid']); + $basic = $layout->leftMenu->addGroup(['Basics', 'icon'=>'cubes']); + $basic->addItem('Button', ['button']); + $basic->addItem('Header', ['header']); -$basic = $layout->leftMenu->addGroup(['Basics', 'icon'=>'cubes']); -$basic->addItem('Button', ['button']); -$basic->addItem('Header', ['header']); + $basic = $layout->leftMenu->addGroup(['Interactivity', 'icon'=>'talk']); + $basic->addItem('JavaScript Events', ['button2']); -$basic = $layout->leftMenu->addGroup(['Interactivity', 'icon'=>'talk']); -$basic->addItem('JavaScript Events', ['button2']); + $f = basename($_SERVER['PHP_SELF']); -$f = basename($_SERVER['PHP_SELF']); + // Would be nice if this would be a link. + $layout->menu->addItem()->add(new \atk4\ui\Button(['View Source', 'teal', 'icon'=>'github'])) + ->setAttr('target', '_blan')->on('click', new \atk4\ui\jsExpression('document.location=[];', ['https://github.com/atk4/ui/blob/develop/demos/'.$f])); -// Would be nice if this would be a link. -$layout->menu->addItem()->add(new \atk4\ui\Button(['View Source', 'teal', 'icon'=>'github'])) - ->setAttr('target', '_blan')->on('click', new \atk4\ui\jsExpression('document.location=[];', ['https://github.com/atk4/ui/blob/develop/demos/'.$f])); + $img = 'https://github.com/atk4/ui/raw/07208a0af84109f0d6e3553e242720d8aeedb784/public/logo.png'; + +} -$img = 'https://github.com/atk4/ui/raw/07208a0af84109f0d6e3553e242720d8aeedb784/public/logo.png'; require_once 'somedatadef.php'; From ae5aa88eda9a352403649be2e003fd8451f2d569 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:48:36 +0200 Subject: [PATCH 15/23] this causes double-initialization. not sure why will figure out later. --- src/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.php b/src/App.php index 3e49a18ad8..0f48e4901b 100644 --- a/src/App.php +++ b/src/App.php @@ -59,7 +59,7 @@ public function __construct($defaults = []) } if (!$this->_initialized) { - $this->init(); + //$this->init(); } // Always run app on shutdown From d7d77973eb82a7d03d6072a7e4cbe3af2f5ca9f4 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:49:02 +0200 Subject: [PATCH 16/23] Forms are now submitted through post. --- src/Callback.php | 15 +++++++++++++-- src/Form.php | 11 +++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Callback.php b/src/Callback.php index 248b85b14d..638fc3fcc8 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -10,6 +10,8 @@ class Callback use TrackableTrait; use AppScopeTrait; + public $POST_trigger = false; + /** * Executes user-specified action when call-back is triggered. * @@ -20,8 +22,14 @@ class Callback */ public function set($callback, $args = []) { - if (isset($_GET[$this->name])) { - return call_user_func_array($callback, $args); + if ($this->POST_trigger) { + if (isset($_POST[$this->name])) { + return call_user_func_array($callback, $args); + } + } else { + if (isset($_GET[$this->name])) { + return call_user_func_array($callback, $args); + } } } @@ -32,6 +40,9 @@ public function set($callback, $args = []) */ public function getURL() { + if ($this->POST_trigger) { + return $_SERVER['REQUEST_URI']; + } return $this->app->url([$this->name=>'callback']); } } diff --git a/src/Form.php b/src/Form.php index 2364b7027f..7297482aa1 100644 --- a/src/Form.php +++ b/src/Form.php @@ -184,7 +184,8 @@ public function init() */ public function loadPOST() { - $this->model->set($this->app->ui_persistence->typecastLoadRow($this->model, $_POST)); + $data = array_intersect_key($_POST, $this->model->elements); + $this->model->set($this->app->ui_persistence->typecastLoadRow($this->model, $data)); } /** @@ -239,7 +240,13 @@ public function jsField($name) public function ajaxSubmit() { - $this->_add($cb = new jsCallback(), ['desired_name'=>'submit']); + $this->_add($cb = new jsCallback(), ['desired_name'=>'submit', 'POST_trigger'=>true]); + + $this->add(new View(['element'=>'input'])) + ->setAttr('name', $cb->name) + ->setAttr('value', 'submit') + ->setAttr('type', 'hidden') + ; $cb->set(function () { $response = $this->hook('submit'); From 61eaf1fcd4877c8fa55682ab3eea37b15ed36446 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:49:54 +0200 Subject: [PATCH 17/23] better handling of double init. Error if no columns. --- src/Grid.php | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/Grid.php b/src/Grid.php index 15e21d605a..ec32175ea1 100644 --- a/src/Grid.php +++ b/src/Grid.php @@ -113,6 +113,13 @@ public function addColumn($name, $columnDef = null, $fieldDef = null) if ($columnDef === null) { $columnDef = $this->_columnFactory($field); + } elseif (is_string($columnDef) || is_array($columnDef)) { + + if (!$this->app) { + throw new Exception(['You can only specify column type by name if Grid is in a render-tree']); + } + + $columnDef = $this->add($columnDef, $name); } else { $this->add($columnDef, $name); } @@ -170,14 +177,16 @@ public function init() { parent::init(); - $this->t_head = $this->template->cloneRegion('Head'); - $this->t_row_master = $this->template->cloneRegion('Row'); - $this->t_totals = $this->template->cloneRegion('Totals'); - $this->t_empty = $this->template->cloneRegion('Empty'); + if (!$this->t_head) { + $this->t_head = $this->template->cloneRegion('Head'); + $this->t_row_master = $this->template->cloneRegion('Row'); + $this->t_totals = $this->template->cloneRegion('Totals'); + $this->t_empty = $this->template->cloneRegion('Empty'); - $this->template->del('Head'); - $this->template->del('Body'); - $this->template->del('Foot'); + $this->template->del('Head'); + $this->template->del('Body'); + $this->template->del('Foot'); + } } /** From bf1c9fc9da61f4a55f6723c61da5fac89181a125 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:50:05 +0200 Subject: [PATCH 18/23] del(array) won't complain about missing keys. --- src/Template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Template.php b/src/Template.php index 33560cae18..82a5838a70 100644 --- a/src/Template.php +++ b/src/Template.php @@ -386,7 +386,7 @@ public function del($tag) { if (is_array($tag)) { foreach ($tag as $t) { - $this->del($t); + $this->tryDel($t); } return $this; From dd98da5369f1302e341c6dc714a9fc32f0e5cc97 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:50:24 +0200 Subject: [PATCH 19/23] re-structure to use array-focused arg. --- src/Column/Link.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Column/Link.php b/src/Column/Link.php index 23fe7d7404..24277bf842 100644 --- a/src/Column/Link.php +++ b/src/Column/Link.php @@ -11,7 +11,7 @@ class Link extends Generic public function __construct($page = []) { - $this->page = $page; + $this->page = $page[0]; } /** @@ -19,6 +19,10 @@ public function __construct($page = []) */ public function getCellTemplate(\atk4\data\Field $f) { + + if (!is_array($this->page)) { + return $this->app->getTag('td', [], $this->app->getTag('a', ['href'=>$this->page], '{$'.$f->short_name.'}')); + } foreach ($this->page as &$val) { $val = str_replace('{$', '___o', $val); $val = str_replace('}', 'c___', $val); From f4ff891577aef052b0ea2ee43bff4c357c914cfc Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 12:50:49 +0000 Subject: [PATCH 20/23] Apply fixes from StyleCI --- demos/init.php | 3 --- src/Callback.php | 1 + src/Column/Link.php | 1 - src/Form.php | 3 +-- src/Grid.php | 1 - src/Persistence/UI.php | 8 +++++--- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/demos/init.php b/demos/init.php index 836c6e237a..fc53535b0e 100644 --- a/demos/init.php +++ b/demos/init.php @@ -9,7 +9,6 @@ $layout = $app->layout; if (isset($layout->leftMenu)) { - $layout->leftMenu->addItem(['Welcome Page', 'icon'=>'gift'], ['index']); $layout->leftMenu->addItem(['Layouts', 'icon'=>'object group'], ['layouts']); @@ -35,8 +34,6 @@ ->setAttr('target', '_blan')->on('click', new \atk4\ui\jsExpression('document.location=[];', ['https://github.com/atk4/ui/blob/develop/demos/'.$f])); $img = 'https://github.com/atk4/ui/raw/07208a0af84109f0d6e3553e242720d8aeedb784/public/logo.png'; - } - require_once 'somedatadef.php'; diff --git a/src/Callback.php b/src/Callback.php index 638fc3fcc8..5de3359f9d 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -43,6 +43,7 @@ public function getURL() if ($this->POST_trigger) { return $_SERVER['REQUEST_URI']; } + return $this->app->url([$this->name=>'callback']); } } diff --git a/src/Column/Link.php b/src/Column/Link.php index 24277bf842..d1b049302c 100644 --- a/src/Column/Link.php +++ b/src/Column/Link.php @@ -19,7 +19,6 @@ public function __construct($page = []) */ public function getCellTemplate(\atk4\data\Field $f) { - if (!is_array($this->page)) { return $this->app->getTag('td', [], $this->app->getTag('a', ['href'=>$this->page], '{$'.$f->short_name.'}')); } diff --git a/src/Form.php b/src/Form.php index 7297482aa1..4a98d88d60 100644 --- a/src/Form.php +++ b/src/Form.php @@ -245,8 +245,7 @@ public function ajaxSubmit() $this->add(new View(['element'=>'input'])) ->setAttr('name', $cb->name) ->setAttr('value', 'submit') - ->setAttr('type', 'hidden') - ; + ->setAttr('type', 'hidden'); $cb->set(function () { $response = $this->hook('submit'); diff --git a/src/Grid.php b/src/Grid.php index ec32175ea1..ce99ae197b 100644 --- a/src/Grid.php +++ b/src/Grid.php @@ -114,7 +114,6 @@ public function addColumn($name, $columnDef = null, $fieldDef = null) if ($columnDef === null) { $columnDef = $this->_columnFactory($field); } elseif (is_string($columnDef) || is_array($columnDef)) { - if (!$this->app) { throw new Exception(['You can only specify column type by name if Grid is in a render-tree']); } diff --git a/src/Persistence/UI.php b/src/Persistence/UI.php index e27d203a19..73fcd748aa 100644 --- a/src/Persistence/UI.php +++ b/src/Persistence/UI.php @@ -65,16 +65,16 @@ public function _typecastSaveField(\atk4\data\Field $f, $value) } /** - * Interpret user-defined input for various types + * Interpret user-defined input for various types. */ public function _typecastLoadField(\atk4\data\Field $f, $value) { switch ($f->type) { case 'boolean': - $value = (boolean)$value; + $value = (bool) $value; break; case 'money': - return str_replace(',','', $value); + return str_replace(',', '', $value); case 'date': case 'datetime': case 'time': @@ -92,12 +92,14 @@ public function _typecastLoadField(\atk4\data\Field $f, $value) throw new Exception(['Incorrectly formatted datetime', 'format' => $format, 'value' => $value, 'field' => $f]); } $v->setTimeZone(new $tz_class(date_default_timezone_get())); + return $v; } else { $v = $dt_class::createFromFormat($format, $value); if ($v === false) { throw new Exception(['Incorrectly formatted date/time', 'format' => $format, 'value' => $value, 'field' => $f]); } + return $v; } From c8a7dc5354a87be3a95a638c610f3b4e42ce4b18 Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 14:51:57 +0200 Subject: [PATCH 21/23] make codeclimate happier --- src/View.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/View.php b/src/View.php index bb2e1c3f56..a056fc79a3 100644 --- a/src/View.php +++ b/src/View.php @@ -815,7 +815,7 @@ public function getJS() { $actions = []; - foreach ($this->_js_actions as $event=>$eventActions) { + foreach ($this->_js_actions as $eventActions) { foreach ($eventActions as $action) { $actions[] = $action; } From 94b71e703f3c2a6a0ded096755621740e55b9e0f Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 15:39:04 +0200 Subject: [PATCH 22/23] minor fix --- src/View.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/View.php b/src/View.php index b647e0f74e..3ffe44e718 100644 --- a/src/View.php +++ b/src/View.php @@ -725,7 +725,7 @@ public function getHTML() * * @return jQuery */ - public function js($when = null, $action = null) + public function js($when = null, $action = null, $extra = null) { $chain = new jQuery($this); From 6989dd5c36f5a0e8ca724eb3436ac17dd99e1ccc Mon Sep 17 00:00:00 2001 From: Romans Malinovskis Date: Sat, 25 Feb 2017 15:50:17 +0200 Subject: [PATCH 23/23] fix problem i introduced myself --- src/View.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/View.php b/src/View.php index 3ffe44e718..a22d3f0858 100644 --- a/src/View.php +++ b/src/View.php @@ -725,7 +725,7 @@ public function getHTML() * * @return jQuery */ - public function js($when = null, $action = null, $extra = null) + public function js($when = null, $action = null) { $chain = new jQuery($this); @@ -733,8 +733,8 @@ public function js($when = null, $action = null, $extra = null) if ($when === true) { $this->_js_actions[$when][] = $chain; - if ($extra) { - $this->_js_actions[$when][] = $extra; + if ($action) { + $this->_js_actions[$when][] = $action; } return $chain; @@ -746,7 +746,7 @@ public function js($when = null, $action = null, $extra = null) // next - binding on a specific event $action = (new jQuery($this)) - ->bind($when, new jsFunction([$chain, $extra, 'preventDefault'=>true, 'stopPropagation'=>true])); + ->bind($when, new jsFunction([$chain, $action, 'preventDefault'=>true, 'stopPropagation'=>true])); $this->_js_actions[$when][] = $action;