diff --git a/.gitmodules b/.gitmodules index 7749162..9403b01 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "addons"] path = addons - url = ./addons + url = https://github.com/atk4/atk4-addons.git diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e8402e --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# sink +Kitchen Sink Project for Agile Toolkit 4.3 - Demonstration of various features. + +## Recommend a good example + +Struggling with implementing something? Ask on forum and if your +problem is common, we will also add the solution here. + +https://forum.agiletoolkit.org + +## Add example yourself + +Fork this repository and create pull request implementing new feature. +Use this as example: + +https://github.com/atk4/sink/pull/3 diff --git a/admin/lib/Admin.php b/admin/lib/Admin.php index 0b322e4..a19763c 100755 --- a/admin/lib/Admin.php +++ b/admin/lib/Admin.php @@ -26,20 +26,23 @@ function init() { } function initLayout(){ parent::initLayout(); - $this->page_object->add('View_ForkMe'); + if(!$_GET['cut_page'])$this->page_object->add('View_ForkMe'); } function initBasic(){ $sm = $this->api->menu->addMenu('Core Features'); - $sm ->addMenuItem('core/hello', 'Hello World'); - $sm ->addMenuItem('core/form', 'Basic Form'); + $sm ->addItem('Hello World', 'core/hello'); + $sm ->addItem('Basic Form', 'core/form'); + $sm ->addItem('Validation', 'core/validation'); + $sm ->addItem('Virtual Page', 'core/vp'); $sm = $this->api->menu->addMenu('JavaScript'); - $sm ->addMenuItem('js/timepicker', 'TimePicker'); - $sm ->addMenuItem('js/boys-n-girls', 'Boys and Girls'); + $sm ->addItem('TimePicker', 'js/timepicker'); + $sm ->addItem('Boys and Girls', 'js/boys-n-girls'); + $sm ->addItem('Dog and Cat', 'js/dog-n-cat'); $sm = $this->api->menu->addMenu('Agile Data'); $sm->addItem('.. vs Slick 3.1.0 (scala)','db/slick'); @@ -47,12 +50,12 @@ function initBasic(){ $sm = $this->api->menu->addMenu('Real-time components'); - $sm ->addMenuItem('realtime/console', 'Real-time console'); + $sm ->addItem('Real-time console', 'realtime/console'); $sm = $this->api->menu->addMenu('Miscelanious'); - $sm ->addMenuItem('misc/alert-button', 'Alert Button'); - $sm ->addMenuItem('misc/virtual-pages', 'Virtual Pages'); + $sm ->addItem('Alert Button', 'misc/alert-button'); + $sm ->addItem('Virtual Pages', 'misc/virtual-pages'); try { $this->dbConnect(); diff --git a/admin/page/core/validation.php b/admin/page/core/validation.php new file mode 100644 index 0000000..f21ba32 --- /dev/null +++ b/admin/page/core/validation.php @@ -0,0 +1,153 @@ +add('View_Hint')->set('This example clarifies the usage of the validation hooks in ATK 4.3+'); + + $t = $this->add('Tabs'); + + $t->addTabURL('./submit','onSubmit'); + $t->addTabURL('./validator','validator'); + $t->addTabURL('./validator2','validator2'); + $t->addTabURL('./validator3','validator3'); + $t->addTabURL('./callback','callback'); + $t->addTabURL('./class','class'); + } + + /** + * This demonstrates backwards-compatible validation on submit. + * http://book.agiletoolkit.org/views/form/validation.html#form-validation-examples + * + * Although documentation is using older method displayFieldError(), + * which should be updated to simply error() + */ + function page_submit() { + $f = $this->add('Form'); + $f->addField('large_number'); + $f->addField('mandatory'); + $f->addField('mandatory2')->validateNotNull(); + $f->addSubmit(); + + $f->onSubmit(function($f){ + if($f['large_number']<1000)return $f->error('large_number','is not large enough'); + if(!$f['mandatory'])return $f->error('mandatory','write something here'); + return 'all good'; + }); + } + + /** + * This takes advantage of a new "validator" class, which is described here + * http://book.agiletoolkit.org/controller/validator.html + * + * We are using field->validate() method, which basically will associate + * validation string with the field + */ + function page_validator() { + $f = $this->add('Form'); + $f->addField('large_number')->validate('>1000?is not large enough'); + $f->addField('mandatory')->validate('required'); + $f->addField('mandatory2')->validateNotNull(); + $f->addSubmit(); + + $f->onSubmit(function($f){ + return 'all good'; + }); + } + + /** + * This also uses Controller_Validator, but calls it through $form->validate() + * This method allows you to define multiple rules with a single call and is + * directly passed to is(). Also when calling through validate(), this + * also binds validation to 'validate' hook. + */ + function page_validator2() { + $f = $this->add('Form'); + $f->addField('large_number'); + $f->addField('mandatory'); + $f->addField('mandatory2')->validateNotNull(); + + $f->validate([ + 'large_number|>1000?is not large enough', + 'mandatory|required' + ]); + + $f->addSubmit(); + + $f->onSubmit(function($f){ + return 'all good'; + }); + } + + /** + * This approach uses validator manually, and performs validation from onSubmit + * method, but still uses the Controller_Validator. I recommend that you + * use validator/validator2 approach. + */ + function page_validator3() { + $f = $this->add('Form'); + $f->addField('large_number'); + $f->addField('mandatory'); + $f->addField('mandatory2')->validateNotNull(); + + + $f->addSubmit(); + + $f->onSubmit(function($f){ + $f->add('Controller_Validator')->is([ + 'large_number|>1000?is not large enough', + 'mandatory|required' + ])->now(); + + return 'all good'; + }); + } + + /** + * Controller_Validator also supports your own callbacks, like below. + * I am also using post-validate hook for my manual call-back, because + * it's what validate() method uses. + */ + function page_callback() { + $f = $this->add('Form'); + $f->addField('large_number')->validate(function($v,$a){ if($a<1000)$v->fail('is not large enough'); }); + $f->addField('mandatory'); + $f->addHook('post-validate', function($f){ + if(!$f['mandatory']) + $f->error('mandatory','write something here'); + + /* + * also works, but longer + throw $this->exception('write something here','ValidityCheck') + ->setField('mandatory'); + */ + }); + $f->addField('mandatory2')->validateField(function($f){ if(!$f->get())return 'must not be null'; }); + $f->addSubmit(); + + $f->onSubmit(function($f){ + return 'all good'; + }); + } + + /** + * This demonstrates how validation works in a custom class, with redefining + * performValidation method(). + */ + function page_class() { + $f = $this->add('Form'); + $f->addField('LargeNumber','large_number'); + $f->addField('mandatory'); + $f->addField('mandatory2')->validateNotNull(); + $f->addSubmit(); + + $f->onSubmit(function($f){ + return 'all good'; + }); + } +} + +class Form_Field_LargeNumber extends Form_Field_Line { + function performValidation() { + if($this->get()<1000) $this->form->error($this->short_name,'too small'); + } +} diff --git a/admin/page/js/dogncat.php b/admin/page/js/dogncat.php new file mode 100644 index 0000000..068852e --- /dev/null +++ b/admin/page/js/dogncat.php @@ -0,0 +1,33 @@ +add('View_Box')->set('Nothing'); + + if($_GET['dog'])$vm->set('It is the dog'); + if($_GET['cat'])$vm->set('It is the cat'); + + $button=$this->add('Button'); + $button->set('Dog'); + $button->on('click',$vm->js()->reload(['dog'=>true])); + + $button=$this->add('Button'); + $button->set('Cat'); + $button->on('click',$vm->js()->reload(['cat'=>true])); + + } +} diff --git a/admin/page/misc/virtualpages.php b/admin/page/misc/virtualpages.php index e19b5c0..c1d1fcc 100644 --- a/admin/page/misc/virtualpages.php +++ b/admin/page/misc/virtualpages.php @@ -5,7 +5,81 @@ class page_misc_virtualpages extends Page { function init() { parent::init(); - $this->add('View_Info')->set('This is main page'); + + // Demo 1 + $this->add('View_Info')->set('You can get the manual URL of a virtual page and use it as you wish'); + + $vp = $this->add('VirtualPage'); + $vp->set(function($p){ + $p->add('View_Info')->set('you are now on a virtual page'); + }); + + $this->add('Button')->link($vp->getURL()); + + // Demo 2 + + $this->add('HR'); + + $this->add('View_Info')->set('VirtualPage does not normally render, but you can add it into various views for + som added effects. For example if you add $vp into a Button, you can use click() method. The second button will only respond if you move your mouse cursor directly over the icon'); + + $this->add('Button')->set('Button 1')->add('VirtualPage')->bindEvent()->set(function($p){ + $p->add('View_Info')->set('Clicked button 1'); + }); + + $this->add('Button')->set(['Button 2','icon'=>'check'])->add('VirtualPage')->bindEvent('Mouseovered the icon?','mouseenter','.icon-check')->set(function($p){ + $p->add('View_Info')->set('Hovered icon of Button 2'); + }); + + $this->add('HR'); + + // Demo 3 + + $this->add('View_Info')->set('VirtualPage is also integrated into other views in Agile Toolkit. For example on() event uses Virtual Page for doing call-backs.'); + + // Call-back is funneled into enternal VirtualPage. + $this->add('Button')->set('click me')->on('click',function($b){ return $b->fadeOut('slow'); }); + + $this->add('Button')->set(['hover my icon', 'icon'=>'check'])->on('mouseleave','.icon-check',function($b){ return $b->fadeOut('slow'); }); + + // Another example is Real-time Console that also uses Virtual Page. + + $this->add('HR'); + + // Demo 4 + + $this->add('View_Info')->set('As the previous example(s) use custom events and custom selectors, we can now combine virtual page with grid'); + + $gr = $this->add('SampleGrid'); + $gr->addColumn('button','test1'); + if(isset($_GET['test1']))$this->js()->univ()->successMessage('Old-style buttons on a grid require checking of _GET argument and executing. ID='.$_GET['test1'])->execute(); + + + $gr->addColumn('template','test2')->setTemplate(''); + $gr->on('click', '.test2', function($js, $data){ return $js->univ()->successMessage('With on() and virtual page, we know id='.$data['id']); }); + + + $vp = $this->add('VirtualPage'); + $gr->addColumn('template','test3')->setTemplate(''); + $gr->on('click', '.test3')->univ()->dialogURL('Dialog here', [ $vp->getURL(), 'id'=>$this->js()->_selectorThis()->data('id')]); + $vp->set(function($p){ + $p->add('View_Info')->set('Using virtual page we can now get id='.$_GET['id']); + }); + + + $vp = $gr->add('VirtualPage'); + $vp->addColumn('test4','Delete', ['icon'=>'trash']); + $gr->js(true)->_selector('.pb_test4')->addClass('atk-swatch-red'); + $vp->set(function($p){ + $p->add('View_Info')->set('A more integrated way to get id='.$p->id); + }); + + + $this->add('HR'); + + // Demo 5 + + $this->add('View_Info')->set('Virtual pages are used to create page within a page. Here you see a button, that opens a "virtual page" that does not have an URL of its own, but will be triggered by a view and will take over rendering, when the dialog is displayed.'); $vp1 = $this->add('VirtualPage','vp1'); $vp1->set(function ($p1) { @@ -20,5 +94,29 @@ function init() { }); $this->add('Button')->set('Open Virtual Page1')->js('click')->univ()->frameURL('Page 1',$vp1->getURL(),['width'=>500,'height'=>300]); + + + + + } + + + +} + +class SampleGrid extends Grid { + function init(){ + parent::init(); + + $m = $this->add('Model'); + $m->addField('name'); + $m->addField('surname'); + $m->setSource('Array',[ + ['name'=>'Vinny', 'surname'=>'Sihra'], + ['name'=>'Zoe', 'surname'=>'Shatwell'], + ['name'=>'Darcy', 'surname'=>'Wild'], + ]); + + $this->setModel($m); } } diff --git a/composer.json b/composer.json index f379e09..b55a76f 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "type":"project", "require":{ - "atk4\/atk4":"dev-master", + "atk4\/atk4":"*", "educoder\/pest":"1.0.0" }, "autoload":{ diff --git a/composer.lock b/composer.lock index e70a3e9..bb14d01 100644 --- a/composer.lock +++ b/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "cc1e5c868abb597ea8dfce72da8a4e39", - "content-hash": "7948fc81034b786f3e24890de05c9906", + "hash": "62d5a4a89ba821f1b8296ab15dd52087", + "content-hash": "7f252e95e6df21b877b8ff39b785f2a2", "packages": [ { "name": "atk4/atk4", - "version": "dev-master", + "version": "4.3.2", "source": { "type": "git", "url": "https://github.com/atk4/atk4.git", - "reference": "443f110e1f08d81d3785a0f9da18f42da69c297e" + "reference": "0eb774a28165db5cca5b0520851d212f11ade6f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/atk4/atk4/zipball/443f110e1f08d81d3785a0f9da18f42da69c297e", - "reference": "443f110e1f08d81d3785a0f9da18f42da69c297e", + "url": "https://api.github.com/repos/atk4/atk4/zipball/0eb774a28165db5cca5b0520851d212f11ade6f9", + "reference": "0eb774a28165db5cca5b0520851d212f11ade6f9", "shasum": "" }, "type": "library", @@ -39,7 +39,7 @@ "atk4", "framework" ], - "time": "2016-02-04 18:10:53" + "time": "2016-02-29 12:21:49" }, { "name": "educoder/pest", @@ -87,9 +87,7 @@ "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "atk4/atk4": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": [], diff --git a/docs/database.sql b/docs/database.sql index 684ed97..1502dd1 100644 --- a/docs/database.sql +++ b/docs/database.sql @@ -74,15 +74,6 @@ VALUES UNLOCK TABLES; -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - - # Dump of table item # ------------------------------------------------------------ @@ -190,13 +181,6 @@ UNLOCK TABLES; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; - /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;