├── .gitignore ├── .travis.yml ├── Form.php ├── FormAsset.php ├── FormBase.php ├── FormBuilder.php ├── FormBuilderAsset.php ├── FormPHPAsset.php ├── LICENSE ├── Module.php ├── README.md ├── assets ├── form-builder │ ├── css │ │ └── forms │ │ │ ├── form-builder.css │ │ │ └── quill.snow.css │ └── js │ │ └── forms │ │ ├── Sortable.min.js │ │ ├── clipboard.js │ │ ├── clipboard.min.js │ │ ├── controller.js │ │ ├── examples.js │ │ ├── field.js │ │ ├── form.js │ │ ├── form.module.response.js │ │ ├── helpers.js │ │ ├── quill.js │ │ ├── quill.min.js │ │ └── test.js └── form │ └── js │ └── forms │ ├── creator.js │ ├── field.js │ ├── fields.js │ ├── form.js │ ├── forms.min.js │ ├── fp.js │ └── helpers.js ├── bootstrap ├── ActiveField.php └── ActiveForm.php ├── codeception.yml ├── commands └── InitController.php ├── composer.json ├── config ├── params.php ├── test.php └── test_db.php ├── controllers └── ModuleController.php ├── karma.conf.js ├── messages └── pl │ └── builder.php ├── migrations ├── RbacController.php ├── forms.sql ├── m170101_000000_create_form_table.php └── m180101_000000_create_user_table.php ├── models ├── DynamicFormModel.php ├── FormModel.php └── FormModelSearch.php ├── package.json ├── rbac └── AuthorFormRule.php ├── tests ├── helpers.html ├── js │ ├── SpecRunner.html │ ├── fieldTest.js │ ├── formTest.js │ ├── helpersTest.js │ ├── lib │ │ └── jasmine-2.6.2 │ │ │ ├── boot.js │ │ │ ├── console.js │ │ │ ├── jasmine-html.js │ │ │ ├── jasmine.css │ │ │ ├── jasmine.js │ │ │ └── jasmine_favicon.png │ └── src │ │ ├── Player.js │ │ └── Song.js └── php │ ├── _bootstrap.php │ ├── _data │ └── dump.sql │ ├── _support │ ├── AcceptanceTester.php │ ├── FunctionalTester.php │ ├── Helper │ │ ├── Acceptance.php │ │ ├── Functional.php │ │ └── Unit.php │ ├── NoGuy.php │ ├── UnitTester.php │ └── _generated │ │ ├── AcceptanceTesterActions.php │ │ ├── FunctionalTesterActions.php │ │ ├── NoGuyActions.php │ │ └── UnitTesterActions.php │ ├── acceptance.suite.yml.example │ ├── acceptance │ └── _bootstrap.php │ ├── functional.suite.yml.example │ ├── functional │ ├── AccessCept.php │ ├── FormsCest.php │ └── _bootstrap.php │ ├── unit.suite.yml │ └── unit │ ├── FormBaseTest.php │ ├── FormCreateTest.php │ ├── FormModelTest.php │ ├── FormUpdateTest.php │ └── _bootstrap.php └── views ├── builder ├── _manual.php ├── _sidebar.php ├── main.php └── options │ ├── button │ ├── _add-item.php │ ├── _add-to-form.php │ ├── _back.php │ ├── _clone-item.php │ ├── _delete-item.php │ ├── _delete.php │ ├── _save-form.php │ └── _showme.php │ ├── description.php │ ├── field │ ├── _backgroundcolor.php │ ├── _class.php │ ├── _color.php │ ├── _description.php │ ├── _help-block.php │ ├── _id.php │ ├── _label.php │ ├── _name.php │ ├── _placeholder.php │ ├── _rows.php │ ├── _text.php │ ├── _type.php │ ├── _value.php │ ├── _width-and-require.php │ └── _width.php │ ├── form.php │ ├── input.php │ ├── item │ ├── _checked.php │ ├── _selected.php │ ├── _text.php │ └── _value.php │ ├── multi-field.php │ ├── select.php │ ├── submit.php │ └── textarea.php ├── form_js.php ├── form_php.php ├── index.php └── module ├── create.php ├── end.php ├── gridview.php ├── index.php ├── list.php ├── update.php ├── user.php ├── view.php └── view_only_once.php /.gitignore: -------------------------------------------------------------------------------- 1 | # phpstorm project files 2 | .idea 3 | /tags 4 | # netbeans project files 5 | nbproject 6 | 7 | # zend studio for eclipse project files 8 | .buildpath 9 | .project 10 | .settings 11 | 12 | # windows thumbnail cache 13 | Thumbs.db 14 | 15 | # composer itself is not needed 16 | composer.phar 17 | package-lock.json 18 | 19 | # Mac DS_Store Files 20 | .DS_Store 21 | 22 | # phpunit itself is not needed 23 | phpunit.phar 24 | # local phpunit config 25 | /phpunit.xml 26 | 27 | tests/php/_output/* 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Travis CI configuration file. 2 | 3 | language: php 4 | 5 | php: 6 | # 5.6 7 | - 7.0 8 | # faster builds on new travis setup not using sudo 9 | sudo: false 10 | # cache vendor dirs 11 | cache: 12 | directories: 13 | - $HOME/.composer/cache 14 | 15 | install: 16 | - pwd 17 | - travis_retry composer self-update && composer --version 18 | - travis_retry composer global require "fxp/composer-asset-plugin:^1.3.1" 19 | - travis_retry composer global require "codeception/codeception=2.2.*" 20 | - composer create-project "yiisoft/yii2-app-basic:@dev" frameworks-yii-basic --no-dev 21 | # export PATH="$HOME/.composer/vendor/bin:$PATH" 22 | - travis_retry composer install --prefer-dist --no-interaction 23 | - composer show -i 24 | 25 | before_script: 26 | - pwd && ls 27 | - ls ~/.composer/vendor -s -a 28 | script: 29 | - php ~/.composer/vendor/bin/codecept run unit 30 | # vendor/bin/codecept -c vendor/pceuropa/yii2-forms run unit 31 | after_failure: 32 | # cat codeception/_app/runtime/logs/* 33 | -------------------------------------------------------------------------------- /Form.php: -------------------------------------------------------------------------------- 1 | 19 | * @version 3.0.2 20 | * @license MIT 21 | * 22 | * https://github.com/pceuropa/yii2-forum 23 | * Please report all issues at GitHub 24 | * https://github.com/pceuropa/yii2-forum/issues 25 | * 26 | * Usage example: 27 | * ~~~ 28 | * echo \pceuropa\forms\form::widget([ 29 | * 'form' => ',{}' 30 | * ]); 31 | * 32 | * echo \pceuropa\forms\form::widget([ 33 | * 'formId' => 1, 34 | * ]); 35 | * ~~~ 36 | * echo \pceuropa\forms\Form::widget([ 37 | * FormBuilder requires Yii 2 38 | * http://www.yiiframework.com 39 | * https://github.com/yiisoft/yii2 40 | * 41 | */ 42 | 43 | class Form extends Widget { 44 | /** 45 | * @var int Id of form. If set, widget take data from FormModel. 46 | * @see pceuropa\models\FormModel 47 | */ 48 | public $formId = null; 49 | 50 | /** 51 | * @var array|string JSON Object representing the form body 52 | */ 53 | public $body = '{}'; 54 | 55 | /** 56 | * @var string Type render js|php 57 | * @since 1.0 58 | */ 59 | public $typeRender = 'php'; 60 | 61 | /** 62 | * Initializes the object. 63 | * @return void 64 | * @see Widget 65 | */ 66 | public function init() { 67 | parent::init(); 68 | if (is_int($this->formId)) { 69 | $form = FormModel::FindOne($this->formId); 70 | $this->body = $form->body; 71 | } 72 | $this->body = Json::decode($this->body); 73 | } 74 | 75 | /** 76 | * Executes the widget. 77 | * @since 1.0 78 | * @return function 79 | */ 80 | public function run() { 81 | if ($this->typeRender === 'js') { 82 | return $this->jsRender($this->body); 83 | } 84 | return $this->phpRender($this->body); 85 | } 86 | 87 | 88 | /** 89 | * Render form by PHP and add rules 90 | * TODO: each rule for checkbox 91 | * @param array $form 92 | * @return View Form 93 | */ 94 | public function phpRender($form) { 95 | 96 | $data_fields = FormBase::onlyCorrectDataFields($form); 97 | $DynamicModel = new DynamicModel(ArrayHelper::getColumn($data_fields, 'name')); 98 | 99 | foreach ($data_fields as $v) { 100 | 101 | if (isset($v["name"]) && $v["name"]) { 102 | 103 | if (isset($v["require"]) && $v["require"]) { 104 | $DynamicModel->addRule($v["name"], 'required'); 105 | } 106 | $rule = FormBase::ruleType($v); 107 | $DynamicModel->addRule($v["name"], $rule); 108 | 109 | 110 | } 111 | } 112 | 113 | return $this->render('form_php', [ 114 | 'form_body' => $form, 115 | 'model' => $DynamicModel 116 | ]); 117 | } 118 | 119 | /** 120 | * Render form by JavaScript 121 | * @param array $form 122 | * @return View 123 | */ 124 | public function jsRender($form) { 125 | return $this->render('form_js', ['form' => $form]); 126 | } 127 | } 128 | ?> 129 | -------------------------------------------------------------------------------- /FormAsset.php: -------------------------------------------------------------------------------- 1 | 6 | * @version 1.4.1 7 | * @license MIT 8 | * https://github.com/pceuropa/yii2-forum 9 | * Please report all issues at GitHub 10 | * https://github.com/pceuropa/yii2-forum/issues 11 | */ 12 | class FormAsset extends \yii\web\AssetBundle { 13 | public $sourcePath = '@vendor/pceuropa/yii2-forms/assets/form'; 14 | public $baseUrl = '@web'; 15 | public $js = [ 16 | 'js/forms/helpers.js', 17 | 'js/forms/form.js', 18 | 'js/forms/field.js', 19 | 'js/forms/fp.js', 20 | ]; 21 | public $depends = [ 22 | 'yii\web\YiiAsset', 23 | 'yii\bootstrap\BootstrapAsset', 24 | ]; 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /FormBase.php: -------------------------------------------------------------------------------- 1 | 9 | * @version 1.5.1 10 | * @license MIT 11 | * https://github.com/pceuropa/yii2-forum 12 | * Please report all issues at GitHub 13 | * https://github.com/pceuropa/yii2-forum/issues 14 | */ 15 | 16 | class FormBase { 17 | 18 | /** 19 | * Filter fields array and retun only fields with attribute name (data fields) 20 | * @param array $array Array represent elements of form 21 | * @return array Only fields with attribute name 22 | */ 23 | public function gridViewItemsForm($array = []){ 24 | yield ['class' => 'yii\grid\SerialColumn']; 25 | 26 | foreach ($array as $key_row => $row) { 27 | foreach ($row as $key => $v) { 28 | $field = $array[$key_row][$key]; 29 | if (ArrayHelper::keyExists('name', $field) ){ 30 | yield $field['name']; 31 | } 32 | } 33 | } 34 | yield [ 35 | 'class' => 'yii\grid\ActionColumn', 36 | 'template' => ' {delete}', 37 | 'buttons' => [ 38 | 'delete' => function ($url, $model) { 39 | return Html::a( 40 | '', 41 | ['deleteitem', 'id'=> $model['id'], 'form' => $_GET['id']], 42 | [ 43 | 'data-method' => 'post', 44 | 'data-confirm' => 'Are you sure ?' 45 | ]); 46 | } 47 | ] 48 | ]; 49 | } 50 | 51 | public function onlyCorrectDataFields($array = []){ 52 | $data_fields = []; 53 | foreach ($array as $key_row => $row) { 54 | foreach ($row as $key => $v) { 55 | $field = $array[$key_row][$key]; 56 | 57 | if (ArrayHelper::keyExists('name', $field) ){ 58 | array_push($data_fields, $field); 59 | } 60 | } 61 | } 62 | return $data_fields; 63 | } 64 | 65 | /** 66 | * Generate table shema need to create table 67 | * Get array with data fields and 68 | * @param array $array Data fields 69 | * @return array 70 | */ 71 | public static function tableSchema($array = []){ 72 | $schema = []; 73 | 74 | foreach ($array as $row) { 75 | foreach ($row as $v) { 76 | 77 | if ( isset($v['name']) ){ 78 | $schema[$v['name']] = ($v['field'] === 'textarea') ? 'text' : 'string'; 79 | } 80 | } 81 | } 82 | return $schema; 83 | } 84 | 85 | /** 86 | * Return column type. 87 | * Need to add column in table SQL 88 | * @param array $field Data one field. 89 | * @return null|string 90 | */ 91 | public function getColumnType($field){ 92 | 93 | if (!ArrayHelper::keyExists('field', $field)){ 94 | return null; 95 | } 96 | $type = [ 97 | 'input' => [ 98 | 'text' => 'string', 99 | 'email' => 'string', 100 | 'password' => 'string', 101 | 'date' => 'string', 102 | 'number' => 'integer', 103 | 'url' => 'string', 104 | 'tel' => 'string', 105 | 'url' => 'string', 106 | 'color' => 'string', 107 | 'range' => 'string', 108 | 'url' => 'string', 109 | ], 110 | 'textarea' => 'text', 111 | 'checkbox' => 'string', 112 | 'radio' => 'string', 113 | 'select' => 'string', 114 | ]; 115 | 116 | 117 | if ($field['field'] === 'input'){ 118 | return $type[ $field['field'] ][ $field['type'] ]; 119 | } 120 | 121 | return $type[ $field['field'] ]; 122 | 123 | } 124 | 125 | /** 126 | * Return validation rule type. 127 | * Need to dynamic model validation 128 | * @param array $f Data field. 129 | * @return null|array 130 | */ 131 | public function ruleType($f){ 132 | 133 | $types = ['input' => [ 134 | 'text' => 'string', 135 | 'email' => 'email', 136 | 'password' => 'string', 137 | 'date' => 'date', 138 | 'number' => 'integer', 139 | 'url' => 'url', 140 | 'tel' => 'string', 141 | 'color' => 'string', 142 | 'range' => 'string', 143 | ], 144 | 'textarea' => 'string', 145 | 'checkbox' => 'each' , 146 | 'radio' => 'string', 147 | 'select' => 'string', 148 | ]; 149 | 150 | if ($f['field'] === 'input'){ 151 | return $types[$f['field']][$f['type']]; 152 | } 153 | 154 | return $types[$f['field']]; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /FormBuilder.php: -------------------------------------------------------------------------------- 1 | 16 | * @version 3.0.2 17 | * @license MIT 18 | * 19 | * https://github.com/pceuropa/yii2-forms 20 | * Please report all issues at GitHub. Thank for Your time. 21 | * https://github.com/pceuropa/yii2-forms/issues 22 | * 23 | * FormBuilder requires Yii 2 24 | * http://www.yiiframework.com 25 | * https://github.com/yiisoft/yii2 26 | * 27 | * For yii2-form documentation go to 28 | * https://pceuropa.net/yii2S-extensions/yii2-forms/manual 29 | * 30 | */ 31 | 32 | class FormBuilder extends Widget { 33 | 34 | /** 35 | * @var array preLoaded data of form 36 | */ 37 | public $formData = null; 38 | 39 | /** 40 | * @var bool If true FormBuilder set test data on begin 41 | * @since 1.0 42 | */ 43 | public $test_mode = false; 44 | 45 | /** 46 | * @var bool If true - only basic options of form and fields 47 | * @since 1.0 48 | */ 49 | public $easy_mode = true; 50 | 51 | /** 52 | * @var bool If true - hide options dont need for only generator html|Yii2 code 53 | * @since 1.0 54 | */ 55 | public $generator_mode = false; 56 | 57 | /** 58 | * @var bool If true - form can send email response 59 | * @since 1.4 60 | */ 61 | public $send_email = false; 62 | 63 | /** 64 | * @var array Configuration data for JavaScript assets 65 | * @since 1.0 66 | */ 67 | public $jsConfig = []; 68 | 69 | /** 70 | * @var array configuration data for php render 71 | * @since 1.0 72 | */ 73 | private $options = []; 74 | 75 | /** 76 | * @var string DB connections 77 | */ 78 | public $db = 'db'; 79 | 80 | /** 81 | * @var string The database table storing the forms 82 | */ 83 | public $formTable = '{{%forms}}'; 84 | 85 | /** 86 | * @var string The database table storing the data from forms 87 | */ 88 | public $formDataTable = 'form_'; 89 | 90 | /** 91 | * @var FormModel Model data 92 | * @since 1.0 93 | */ 94 | public $model; 95 | 96 | /** 97 | * @var bool Response from backend to message success 98 | * @since 1.0 99 | */ 100 | public $success = false; // for response 101 | 102 | /** 103 | * @var bolean If false - hide button save form 104 | */ 105 | public $hide_button_form_save = false; 106 | 107 | /** 108 | * Initializes the object. 109 | * Variables and functions init 110 | * @since 1.0 111 | * 112 | */ 113 | public function getDb() { 114 | return Yii::$app->{$this->db}; 115 | } 116 | 117 | 118 | public function init() { 119 | parent::init(); 120 | 121 | $this->registerTranslations(); 122 | $this->model = new FormModel(); 123 | if ($this->formData !== null) { 124 | $this->load($this->formData); 125 | } 126 | 127 | $this->options = [ 128 | 'easy_mode' => $this->easy_mode, 129 | 'test_mode' => $this->test_mode, 130 | 'generator_mode' => $this->generator_mode, 131 | 'send_email' => $this->send_email, 132 | 'hide_button_form_save' => $this->hide_button_form_save, 133 | 'jsConfig' => $this->jsConfig 134 | ]; 135 | } 136 | 137 | /** 138 | * Executes the widget. 139 | * @since 1.0 140 | * @return void 141 | */ 142 | public function run() { 143 | return $this->formBuilderRender(); 144 | } 145 | 146 | /** 147 | * Populates the model with input ajax data. 148 | * @since 1.0 149 | * @param object $data Data from request post 150 | * @return null 151 | */ 152 | public function load($form) { 153 | foreach ($form as $key => $value) { 154 | $this->model[$key] = $form[$key]; 155 | } 156 | $this->model->author = (isset(Yii::$app->user->identity->id)) ? Yii::$app->user->identity->id : null; 157 | } 158 | 159 | /** 160 | * Creates an yii\db\ActiveQueryInterface instance for query purpose. 161 | * @since 1.0 162 | * @param int $id Data from request post 163 | * @return null 164 | */ 165 | public function findModel(int $id) { 166 | $this->model = $this->model->findModel($id); 167 | } 168 | 169 | /** 170 | * Saves the current record. 171 | * @since 1.0 172 | * @return array|bool Return message error or true if saved corretly 173 | */ 174 | public function save() { 175 | if (!($this->success = $this->model->save())) { 176 | return $this->success = $this->model->getFirstErrors(); 177 | } 178 | return $this->success; 179 | } 180 | /** 181 | * Populates the model with input data. 182 | * @since 1.0 183 | * @see FormBase::tableSchema 184 | * @param string Json form 185 | * @return array Return table shema 186 | */ 187 | public function tableSchema($form_body) 188 | { 189 | if (!is_string($form_body)) { 190 | return false; 191 | } 192 | 193 | $form_body = Json::decode($form_body); 194 | return FormBase::tableSchema($form_body); 195 | } 196 | 197 | 198 | 199 | /** 200 | * Create table 201 | * Creates a SQL command for creating a new DB table. Execute the SQL statement. 202 | * If table crate table correctly @return array message success 203 | * @since 1.0 204 | * @return object Return json message callback 205 | */ 206 | public function createTable() { 207 | if ($this->success !== true) { 208 | return; 209 | } 210 | 211 | $dynamicFormModel = new DynamicFormModel(); 212 | $dynamicFormModel->createTable( 213 | (string) $table_name = $this->formDataTable . $this->model->form_id, 214 | (array) $table_schema = $this->tableSchema($this->model->body) 215 | ); 216 | } 217 | 218 | /** 219 | * Add column 220 | * Creates a SQL command for adding a new DB column and execute. 221 | * @param array $field 222 | * @return object Return json message callback 223 | */ 224 | public function addColumn(array $field) { 225 | if (!isset($field['name'])) {return $this->success = 'empty name';} 226 | 227 | $column_name = $field['name']; 228 | $column_type = FormBase::getColumnType($field); 229 | $id = $this->model->form_id; 230 | $query = Yii::$app->{$this->db}->createCommand()->addColumn( $this->formDataTable.$id, $column_name, $column_type ); 231 | return $this->execute($query); 232 | } 233 | 234 | /** 235 | * Rename column 236 | * Creates a SQL command for renaming a column and execute. 237 | * @since 1.0 238 | * @param array $name Array with old and new name of the column. 239 | * @return object Return json message callback 240 | */ 241 | public function renameColumn(array $name) { 242 | 243 | if ( !isset($name['old']) && !isset($name['new']) && $name['old'] === $name['new'] ) { 244 | return $this->success = false; 245 | } 246 | 247 | $id = $this->model->form_id; 248 | $query = Yii::$app->db->createCommand()->renameColumn( $this->formDataTable.$id, $name['old'], $name['new']); 249 | 250 | return $this->execute($query); 251 | } 252 | 253 | /** 254 | * Drop column 255 | * Creates a SQL command for dropping a DB column. and execute. 256 | * @since 1.0 257 | * @param string $column The name of the column to be dropped. 258 | * @return object Return json message callback 259 | */ 260 | public function dropColumn(string $column) { 261 | $id = $this->model->form_id; 262 | $query = Yii::$app->db->createCommand()->dropColumn($this->formDataTable.$id, $column); 263 | return $this->execute($query); 264 | } 265 | 266 | 267 | /** 268 | * Executes the SQL statement and @return array callback. 269 | * @since 1.0 270 | * @param object $query 271 | * @return object Return json message callback 272 | */ 273 | public function execute($query) { 274 | try { 275 | $query->execute(); 276 | return $this->success = true; 277 | } catch (Exception $e) { 278 | return $this->success = $e->getMessage(); 279 | } 280 | } 281 | 282 | /** 283 | * Function @return array for ajax callback 284 | * @since 1.0 285 | * @param string $format format response 286 | * @return array Return json message callback 287 | */ 288 | public function response(string $format = 'json') { 289 | \Yii::$app->response->format = $format; 290 | $response = ['success' => $this->success]; 291 | 292 | if ( $this->success === true) { 293 | 294 | try { 295 | $response['url'] = Url::to(['user']); 296 | } catch (\yii\base\InvalidParamException $e) { 297 | $response['url'] = ''; 298 | } 299 | } 300 | return $response; 301 | } 302 | 303 | /** 304 | * Render view 305 | * @since 1.0 306 | * @return void 307 | */ 308 | public function formBuilderRender() { 309 | return $this->render('builder/main', $this->options ); 310 | } 311 | 312 | /** 313 | * Translates a message to the specified language. 314 | * @since 1.0 315 | * @return null 316 | */ 317 | public function registerTranslations() { 318 | Yii::$app->i18n->translations['builder'] = [ 319 | 'class' => 'yii\i18n\PhpMessageSource', 320 | 'sourceLanguage' => 'en-US', 321 | 'basePath' => '@vendor/pceuropa/yii2-forms/messages', 322 | ]; 323 | } 324 | } 325 | ?> 326 | -------------------------------------------------------------------------------- /FormBuilderAsset.php: -------------------------------------------------------------------------------- 1 | 7 | * @version 1.5 8 | * @license MIT 9 | * 10 | * https://github.com/pceuropa/yii2-forum 11 | * Please report all issues at GitHub 12 | * https://github.com/pceuropa/yii2-forum/issues 13 | */ 14 | 15 | class FormBuilderAsset extends \yii\web\AssetBundle { 16 | public $sourcePath = '@vendor/pceuropa/yii2-forms/assets/form-builder'; 17 | public $baseUrl = '@web'; 18 | public $css = [ 19 | // 'css/forms/quill.snow.css', 20 | 'css/forms/form-builder.css', 21 | ]; 22 | public $js = [ 23 | 'js/forms/Sortable.min.js', 24 | //'js/forms/form.min.js', 25 | 'js/forms/helpers.js', 26 | 'js/forms/form.js', 27 | 'js/forms/field.js', 28 | 'js/forms/controller.js', 29 | 30 | 'js/forms/form.module.response.js', 31 | 'js/forms/examples.js', 32 | 'js/forms/test.js', 33 | 34 | 'js/forms/quill.min.js', 35 | 'js/forms/clipboard.min.js', 36 | 37 | ]; 38 | public $depends = [ 39 | 'yii\web\YiiAsset', 40 | 'yii\bootstrap\BootstrapAsset', 41 | ]; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /FormPHPAsset.php: -------------------------------------------------------------------------------- 1 | 6 | * @version 1.4.1 7 | * @license MIT 8 | * https://github.com/pceuropa/yii2-forum 9 | * Please report all issues at GitHub 10 | * https://github.com/pceuropa/yii2-forum/issues 11 | */ 12 | class FormPHPAsset extends \yii\web\AssetBundle { 13 | public $sourcePath = '@vendor/pceuropa/yii2-forms/assets/form'; 14 | public $baseUrl = '@web'; 15 | public $js = [ 16 | 'js/forms/fp.js', 17 | ]; 18 | public $depends = [ 19 | 'yii\web\YiiAsset', 20 | 'yii\bootstrap\BootstrapAsset', 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Rafal Marguzewicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Module.php: -------------------------------------------------------------------------------- 1 | 11 | * @version 3.0.2 12 | * @license MIT 13 | * https://github.com/pceuropa/yii2-forum 14 | * Please report all issues at GitHub 15 | * https://github.com/pceuropa/yii2-forum/issues 16 | * 17 | */ 18 | class Module extends \yii\base\Module{ 19 | 20 | /** 21 | * @ingeritdoc 22 | */ 23 | public $controllerNamespace = 'pceuropa\forms\controllers'; 24 | 25 | /** 26 | * @ingeritdoc 27 | */ 28 | public $defaultRoute = 'module'; 29 | 30 | /** 31 | * @var string Default db connection 32 | */ 33 | public $db = 'db'; 34 | 35 | /** 36 | * @var string The database table storing the forms 37 | */ 38 | public $formTable = '{{%forms}}'; 39 | 40 | /** 41 | * @var string The database table storing the data from forms 42 | */ 43 | public $formDataTable = 'form_'; 44 | 45 | /** 46 | * @var array the list of rights that are allowed to access this module. 47 | * If you modify, you also need to enable authManager. 48 | * http://www.yiiframework.com/doc-2.0/guide-security-authorization.html 49 | * $rules = [ 50 | * [ 51 | * 'actions' => [ 'update', 'delete', 'clone' ], 52 | * 'allow' => true, 53 | * 'roles' => ['updateOwnForm'], 54 | * ], 55 | * [ 56 | * 'actions' => ['user', 'create'], 57 | * 'allow' => true, 58 | * 'roles' => ['user'], 59 | * ] 60 | * ]; 61 | */ 62 | public $rules = [ 63 | [ 64 | 'allow' => true, 65 | 'actions' => [], 66 | 'roles' => ['?'], 67 | ],[ 68 | 'allow' => true, 69 | 'actions' => [], 70 | 'roles' => ['@'], 71 | ] 72 | ]; 73 | 74 | /** 75 | * @var boolean If true after completing the form the message is sent 76 | */ 77 | public $sendEmail = false; 78 | 79 | /** 80 | * @var boolean If true turn on anty bot and check had human sent 81 | */ 82 | public $humanSendOnlyOne = false; 83 | 84 | /** 85 | * @var string The sender's address 86 | */ 87 | public $emailSender = null; 88 | 89 | /** 90 | * @var Boolean If true, you can see action buttons on index action 91 | */ 92 | public $buttonsEditOnIndex = false; 93 | 94 | /** 95 | * @var boolean if true, only necesaire options 96 | */ 97 | public $easyMode = true; 98 | 99 | /** 100 | * @var boolean if true, example form 101 | */ 102 | public $testMode = false; 103 | 104 | public function init() 105 | { 106 | parent::init(); 107 | $this->registerTranslations(); 108 | } 109 | 110 | public function registerTranslations() 111 | { 112 | Yii::$app->i18n->translations['builder'] = [ 113 | 'class' => 'yii\i18n\PhpMessageSource', 114 | 'sourceLanguage' => 'en-US', 115 | 'basePath' => '@pceuropa/forms/messages', 116 | 'fileMap' => [ 'builder' => 'builder.php', ] 117 | ]; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FormBuilder module for Yii2 2 | =================== 3 | 4 | [![Latest Stable Version](https://poser.pugx.org/pceuropa/yii2-forms/v/stable)](https://packagist.org/packages/pceuropa/yii2-forms) [![Total Downloads](https://poser.pugx.org/pceuropa/yii2-forms/downloads)](https://packagist.org/packages/pceuropa/yii2-forms) [![License](https://poser.pugx.org/pceuropa/yii2-forms/license)](https://packagist.org/packages/pceuropa/yii2-forms) 5 | 6 | [FormBuilder DEMO](https://pceuropa.net/yii2-extensions/yii2-forms) 7 | 8 | ## Features 9 | 10 | 11 | 1. Generate forms, surveys, polls, questionnaires (class FormBuilder) 12 | * Drag and drop - Sorting, editing, and deleting items 13 | * CRUD operations by AJAX 14 | * Built-in RBAC component 15 | 16 | 17 | 2. Form render widget (class Form) 18 | * Validation forms (dynamic model) 19 | 20 | 3. Storage data submited from form in databases 21 | * List of forms (GridView) 22 | * Create database tables after create form 23 | * Delete database tables after delete form 24 | * Add table column after add field to form 25 | * Rename table column after change the name of field 26 | * Drop table column after delete field in form 27 | 28 | ## Installation Form Builder 29 | ``` 30 | composer require pceuropa/yii2-forms 31 | ``` 32 | 33 | ## Configuration Form Builder 34 | Make sure that you have properly configured `db` application component in config file and run the following command: 35 | ```bash 36 | $ php yii migrate/up --migrationPath=@vendor/pceuropa/yii2-forms/migrations 37 | ``` 38 | 39 | Add the following code in your configuration file: 40 | ```php 41 | 'modules' => [ 42 | 'forms' => [ 43 | 'class' => 'pceuropa\forms\Module', 44 | ], 45 | ] 46 | ``` 47 | 48 | ## Usage 49 | URLs for the translating tool: 50 | 51 | ``` 52 | /forms/module/index // List of all forms 53 | /forms/module/user // List user's forms 54 | /forms/module/view // Preview form 55 | /forms/module/create // Create form - FormBuilder 56 | /forms/module/update // Update form 57 | /forms/module/delete // Delete form 58 | ``` 59 | 60 | ## Full example configuration Form Builder 61 | 62 | ``` 63 | 'modules' => [ 64 | 'forms' => [ 65 | 'class' => 'pceuropa\forms\Module', 66 | 'db' => 'db', 67 | 'formsTable' => '{{%forms}}', 68 | 'formDataTable' => 'form_', 69 | 'sendEmail' => true, 70 | 'testMode' => false, 71 | 'easyMode' => true, 72 | 'emailSender' => 'info@email.net', 73 | 'rules' => [ 74 | [ 75 | 'actions' => [ 'update', 'delete', 'clone'], 76 | 'allow' => true, 77 | 'roles' => ['updateOwnForm'], // rule only owner can edit form 78 | ], 79 | [ 80 | 'actions' => ['user'], 81 | 'allow' => true, 82 | 'roles' => ['user'], // role only authenticated user can see user's forms 83 | ], 84 | [ 85 | 'actions' => ['create'], 86 | 'allow' => true, 87 | 'roles' => ['@'], // role only logged user can create form 88 | ] 89 | ] 90 | ] 91 | ], 92 | 93 | 'components' => [ 94 | 'authManager' => ['class' => 'yii\rbac\DbManager',], 95 | ] 96 | ``` 97 | 98 | ## Form renderer widget 99 | ``` 100 | use pceuropa\forms\Form; 101 | echo Form::widget([ 102 | 'body' => '[[{"field": "input", "type": "text", "width": "col-md-5", "name": "email", "placeholder": "email"},{"field": "input", "name": "pass", "type": "text", "placeholder": "pass", "width": "col-md-5"},{"field": "submit", "width": "col-md-2", "backgroundcolor": "btn-info", "label": "Submit"}]]', 103 | 'typeRender' => 'php' 104 | ]); 105 | ``` 106 | or 107 | ``` 108 | echo Form::widget([ 109 | 'formId' => 1, // equivalennt 'form' => FormModel::findOne(1)->body 110 | ]); 111 | ``` 112 | 113 | ## Configure RBAC Component 114 | To use generator console, add fallowing code to console config (console.php) 115 | ``` 116 | 'controllerMap' => [ 117 | 'formsrbac' => [ 118 | 'class' => 'pceuropa\forms\migrations\RbacController', 119 | ], 120 | ], 121 | ``` 122 | 123 | 124 | To use RBAC dont forget add fallowing code to app config (web.php or main.php) 125 | ``` 126 | 'components' => [ 127 | 'authManager' => ['class' => 'yii\rbac\DbManager',], 128 | ] 129 | ``` 130 | 131 | Create rbac tables in the database 132 | ```yii migrate --migrationPath=@yii/rbac/migrations``` 133 | 134 | Create RBAC rules and roles. Asssign role user to all users. You can add assign role acction in SignupController 135 | ```php yii formsrbac/generate``` 136 | 137 | 138 | ## Tests 139 | Php tests run 140 | ``` 141 | vendor/bin/codecept run -c vendor/pceuropa/yii2-forms 142 | ``` 143 | or 144 | ``` 145 | cd vendor/pceuropa/yii2-forms 146 | ../../bin/codecept run 147 | ``` 148 | 149 | JavaScript tests run 150 | On begining install depencies: 151 | ``` 152 | cd vendor/pceuropa/yii2-forms 153 | npm install 154 | ``` 155 | 156 | run test 157 | ``` 158 | cd vendor/pceuropa/yii2-forms 159 | karma start 160 | //or if you use karma localy 161 | npm run test 162 | ``` 163 | ## ex. Menu 164 | ``` 165 | [ 166 | 'label' => 'forms', 167 | 'items' => [ 168 | ['label' => 'List of all forms', 'url' => ['/forms/module/index']], 169 | ['label' => 'User\'s forms', 170 | 'url' => ['/forms/module/user'], 171 | 'visible' => !Yii::$app->user->isGuest 172 | ], 173 | ['label' => 'Create form', 'url' => ['/forms/module/create']], 174 | ], 175 | ], 176 | ``` 177 | -------------------------------------------------------------------------------- /assets/form-builder/js/forms/clipboard.js: -------------------------------------------------------------------------------- 1 | import ClipboardAction from './clipboard-action'; 2 | import Emitter from 'tiny-emitter'; 3 | import listen from 'good-listener'; 4 | 5 | /** 6 | * Base class which takes one or more elements, adds event listeners to them, 7 | * and instantiates a new `ClipboardAction` on each click. 8 | */ 9 | class Clipboard extends Emitter { 10 | /** 11 | * @param {String|HTMLElement|HTMLCollection|NodeList} trigger 12 | * @param {Object} options 13 | */ 14 | constructor(trigger, options) { 15 | super(); 16 | 17 | this.resolveOptions(options); 18 | this.listenClick(trigger); 19 | } 20 | 21 | /** 22 | * Defines if attributes would be resolved using internal setter functions 23 | * or custom functions that were passed in the constructor. 24 | * @param {Object} options 25 | */ 26 | resolveOptions(options = {}) { 27 | this.action = (typeof options.action === 'function') ? options.action : this.defaultAction; 28 | this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget; 29 | this.text = (typeof options.text === 'function') ? options.text : this.defaultText; 30 | } 31 | 32 | /** 33 | * Adds a click event listener to the passed trigger. 34 | * @param {String|HTMLElement|HTMLCollection|NodeList} trigger 35 | */ 36 | listenClick(trigger) { 37 | this.listener = listen(trigger, 'click', (e) => this.onClick(e)); 38 | } 39 | 40 | /** 41 | * Defines a new `ClipboardAction` on each click event. 42 | * @param {Event} e 43 | */ 44 | onClick(e) { 45 | const trigger = e.delegateTarget || e.currentTarget; 46 | 47 | if (this.clipboardAction) { 48 | this.clipboardAction = null; 49 | } 50 | 51 | this.clipboardAction = new ClipboardAction({ 52 | action : this.action(trigger), 53 | target : this.target(trigger), 54 | text : this.text(trigger), 55 | trigger, 56 | emitter : this 57 | }); 58 | } 59 | 60 | /** 61 | * Default `action` lookup function. 62 | * @param {Element} trigger 63 | */ 64 | defaultAction(trigger) { 65 | return getAttributeValue('action', trigger); 66 | } 67 | 68 | /** 69 | * Default `target` lookup function. 70 | * @param {Element} trigger 71 | */ 72 | defaultTarget(trigger) { 73 | const selector = getAttributeValue('target', trigger); 74 | 75 | if (selector) { 76 | return document.querySelector(selector); 77 | } 78 | } 79 | 80 | /** 81 | * Returns the support of the given action, or all actions if no action is 82 | * given. 83 | * @param {String} [action] 84 | */ 85 | static isSupported(action = ['copy', 'cut']) { 86 | const actions = (typeof action === 'string') ? [action] : action; 87 | let support = !!document.queryCommandSupported; 88 | 89 | actions.forEach((action) => { 90 | support = support && !!document.queryCommandSupported(action); 91 | }); 92 | 93 | return support; 94 | } 95 | 96 | /** 97 | * Default `text` lookup function. 98 | * @param {Element} trigger 99 | */ 100 | defaultText(trigger) { 101 | return getAttributeValue('text', trigger); 102 | } 103 | 104 | /** 105 | * Destroy lifecycle. 106 | */ 107 | destroy() { 108 | this.listener.destroy(); 109 | 110 | if (this.clipboardAction) { 111 | this.clipboardAction.destroy(); 112 | this.clipboardAction = null; 113 | } 114 | } 115 | } 116 | 117 | 118 | /** 119 | * Helper function to retrieve attribute value. 120 | * @param {String} suffix 121 | * @param {Element} element 122 | */ 123 | function getAttributeValue(suffix, element) { 124 | const attribute = `data-clipboard-${suffix}`; 125 | 126 | if (!element.hasAttribute(attribute)) { 127 | return; 128 | } 129 | 130 | return element.getAttribute(attribute); 131 | } 132 | 133 | module.exports = Clipboard; 134 | -------------------------------------------------------------------------------- /assets/form-builder/js/forms/form.module.response.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Add module send respond message if in form is field 4 | * @param {Form} form 5 | * @param {String} field Optional name of field which active responde textarea 6 | * @return {String} 7 | */ 8 | 9 | var MyFORM = MyFORM || {}; 10 | MyFORM.response = function (){ 11 | 12 | var html = 13 | '
' + 14 | '
' + 15 | '
Email
response
' + 16 | ' ' + 17 | '
'; 18 | 19 | $("#widget-form-options").append(html); 20 | 21 | return function(form){ 22 | $('#response').prop('disabled', form.fields_with_data.indexOf('email') < 0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /assets/form-builder/js/forms/helpers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Helpers functions 3 | * @author Rafal Marguzewicz 4 | * @license MIT 5 | * 6 | * Functions: 7 | capitalizeFirstLetter - capitalize first letter of string 8 | clearObject - delete empty variable of object 9 | clone - copy without reference 10 | each 11 | fibonacci 12 | firstProp 13 | firstValue 14 | getName 15 | getAllProperty 16 | isString 17 | is 18 | isBoolean 19 | isArray 20 | isObject 21 | subString 22 | setData 23 | uniqueName 24 | setAttribute 25 | */ 26 | 27 | "use strict"; 28 | console.log("helpers: 2.0.1"); 29 | var h = { 30 | 31 | /** 32 | * Capitalize First letter of string 33 | * @param {String} s 34 | * @return {String} 35 | */ 36 | capitalizeFirstLetter: function (s) { 37 | return s.charAt(0).toUpperCase() + s.slice(1); 38 | }, 39 | 40 | /** 41 | * Get element by query 42 | * @param {String} query 43 | * @return {htmlelement} 44 | */ 45 | query: function(query){ 46 | return document.querySelector(query); 47 | }, 48 | 49 | /** 50 | * Get element by id 51 | * @param {String} id 52 | * @return {htmlelement} 53 | */ 54 | id: function(id){ 55 | return document.getElementById(id); 56 | }, 57 | 58 | 59 | /** 60 | * Removes empty viariables 61 | * @param {Object} object 62 | * @return {Object} return object without empty variables 63 | */ 64 | clearObject: function(o) { 65 | for (var i in o) { 66 | if (o[i] === null || o[i] === undefined) { 67 | delete o[i]; 68 | } 69 | } 70 | return o; 71 | }, 72 | 73 | /** 74 | * Clone object without reference 75 | * @param {Object} object 76 | * @return {Object} return clone object without reference 77 | */ 78 | clone: function (o) { 79 | var clone = {}; 80 | 81 | for (var prop in o) { 82 | 83 | if( this.isArray(o[prop]) ) { 84 | for (var i = 0; i < o[prop].length; i++) { 85 | clone[prop][i] = o[prop][i]; 86 | } 87 | } else { 88 | clone[prop] = o[prop]; 89 | } 90 | } 91 | return clone; 92 | }, 93 | 94 | 95 | /** 96 | * iterator 97 | * @param {Array} object 98 | * @param {Function} object 99 | * @return {Object} return callaback function on each items 100 | */ 101 | each: function (arr, callback) { 102 | if(this.isArray(arr)) { 103 | var i = 0; 104 | for (i; i < arr.length; i++) { 105 | callback(i, arr[i]); 106 | } 107 | } 108 | }, 109 | 110 | /** 111 | * Fibonacci numbers 112 | * @param {Integer} n 113 | * @param {Function} position of number Fibonacci Fn 114 | * @return {Object} return the sum of the sequence of numbers 115 | */ 116 | fibonacci: function (n) { 117 | return n < 1 ? 0 : n <= 2 ? 1 : this.fibonacci(n - 1) + this.fibonacci(n - 2); 118 | }, 119 | 120 | /** 121 | * Return first property 122 | * @param {Object} n 123 | * @return {Object|false} return first property name or false if param o isnt object 124 | */ 125 | firstProp: function (o) { 126 | if(this.isObject(o)) { 127 | return Object.keys(o)[0]; 128 | } else { 129 | return false 130 | } 131 | }, 132 | 133 | /** 134 | * Return first value 135 | * @param {Object} n 136 | * @return {Object|false} return first value or false if param o isnt object 137 | */ 138 | firstValue: function (o) { 139 | if( this.isObject(o) ) { 140 | return o[Object.keys(o)[0]]; 141 | } else { 142 | return false 143 | } 144 | }, 145 | 146 | 147 | /** 148 | * Helpers for form.js 149 | * @see form.generate 150 | * @param {String} prop Name of property 151 | * @return {Array} return Array of values 152 | */ 153 | getAllProperty: function (prop, o) { 154 | var help = this, result = []; 155 | if(o.length == 0) return result; 156 | 157 | help.each(o, function (i, value) { 158 | if( value.length !== 0 || help.isArray(value) ) { 159 | help.each(value, function (j, v) { 160 | 161 | if ( v.hasOwnProperty(prop) ) { 162 | result.push(v[prop]) 163 | } 164 | }); 165 | } 166 | }); 167 | 168 | return result; 169 | }, 170 | 171 | /** 172 | * Is string 173 | * @param {Mixed} s 174 | * @return {Boolean} return True if param is string 175 | */ 176 | isString: function(s) { 177 | return typeof s === "string" || s instanceof String 178 | }, 179 | 180 | /** 181 | * Is ? 182 | * @param {Mixed} v 183 | * @return {Boolean} return True if param have value 184 | */ 185 | is: function(v) { 186 | return (v !== null && v !== undefined && v !== '') 187 | }, 188 | 189 | /** 190 | * Is boolean ? 191 | * @param {Mixed} v 192 | * @return {Boolean} return True if param is boolean 193 | */ 194 | isBoolean: function (v) { 195 | return typeof v === "boolean" 196 | }, 197 | 198 | /** 199 | * Is Array 200 | * @param {Mixed} o 201 | * @return {Boolean} return True if param is array 202 | */ 203 | isArray: function (o) { 204 | if (!Array.isArray) { 205 | return Object.prototype.toString.call(o) === '[object Array]'; 206 | } else { 207 | return Array.isArray(o); 208 | } 209 | }, 210 | 211 | /** 212 | * Is object 213 | * @param {Mixed} o 214 | * @return {Boolean} return True if param is object 215 | */ 216 | isObject: function (o) { 217 | return typeof o === "object" && this.is(o); 218 | }, 219 | 220 | /** 221 | * Inherit all property 222 | * @param {Object} o 223 | * @param {Object} inherit 224 | * @return {Void} return o 225 | */ 226 | inheritAll: function (o, inherit) { 227 | for (var prop in inherit) { 228 | if (inherit.hasOwnProperty(prop)) { 229 | o[prop] = inherit[prop]; 230 | } 231 | } 232 | }, 233 | 234 | /** 235 | * Replace all chars 236 | * @param {String} o 237 | * @param {String} char Default '_' 238 | * @return {String} return changed string 239 | */ 240 | replaceChars: function (o, char) { 241 | char = char || '_'; 242 | return o.replace( new RegExp("\\W+", 'g'), char) 243 | }, 244 | 245 | 246 | /** 247 | * Substring on sterid 248 | * @param {String} str 249 | * @param {Integer} len Length of string agter cut 250 | * @return {String} render select tag 251 | */ 252 | subString: function(str, len) { 253 | len = len || 10 254 | if(str.length > len) str = str.substring(0,len) + '...'; 255 | return str 256 | }, 257 | 258 | 259 | /** 260 | * Insert element after referenced Node 261 | * @param {HTMLElement} newNode 262 | * @param {HTMLElement} referenceNode 263 | * @returm {HTMLElement} 264 | */ 265 | insertAfter: function(newNode, referenceNode) { 266 | referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); 267 | }, 268 | 269 | /** 270 | * Set attribute with chech is() 271 | * @param {String} attribute - name of attribute which will be add 272 | * @param {String} value - value of attribute 273 | * @returm {undefined} 274 | */ 275 | setAttribute: function(el, attribute, value) { 276 | if( !this.isObject(el) || !this.isString(attribute) ) { 277 | return; 278 | } 279 | if (this.is(value)) { 280 | el.setAttribute(attribute, value) 281 | } 282 | }, 283 | /** 284 | * Set attributes for field 285 | * @param {htmlElement} field 286 | * @param {Array} attributes - list attributes to check 287 | */ 288 | setAttributes: function(field, attributes) { 289 | if (!this.isArray(attributes)) { 290 | throw new TypeError("attributes must be array"); 291 | } 292 | for (var i = 0, len = attributes.length; i < len; i++) { 293 | var attribute = attributes[i] 294 | 295 | if (this.isObject(attribute)) { 296 | this.setAttribute(field, this.firstProp(attribute), this.firstValue(attribute)); 297 | } 298 | 299 | if (this.isString(attribute)) { 300 | this.setAttribute(field, attribute, this.body[attribute]); 301 | } 302 | } 303 | }, 304 | 305 | /** 306 | * Create field, set attributes and append 307 | * @param {String} param - name created Html element 308 | * @param {Array} listAttributes - list of attributes 309 | * @returm {HtmlElement} 310 | */ 311 | createElement: function(param, listAttributes, inner=0) { 312 | var field = document.createElement(param); 313 | this.setAttributes(field, listAttributes); 314 | if (inner) { 315 | field.innerHTML = inner 316 | } 317 | return field; 318 | }, 319 | 320 | /** 321 | * Return unique Name 322 | * @param {String} name Attribute name of field tag 323 | * @param {Array} list of names 324 | * @return {String} render select tag 325 | */ 326 | uniqueName: function(name, list) { 327 | name = this.replaceChars(name) 328 | 329 | function changeName(n) { 330 | if (list.indexOf(n) !== -1) { //sprawdza n w liscie 331 | n = n + '_2'; //jezeli jest dodaje _2 i ponownie wykonuje siebie 332 | return changeName(n); 333 | } else { 334 | return n 335 | } 336 | } 337 | return changeName(name) 338 | }, 339 | }; 340 | 341 | -------------------------------------------------------------------------------- /assets/form-builder/js/forms/test.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) MIT 2017 Rafal Marguzewicz pceuropa.net 2 | var MyFORM = MyFORM || {}; 3 | MyFORM.test = function(form){ 4 | 5 | var version = 'test: 2.0.0', 6 | object_form = { 7 | "title": "Title-test", 8 | "method": "get", 9 | "language": "Polish-test", 10 | 'url': 'url-cos-tam', 11 | "body": [ 12 | [ 13 | { 14 | "field": "description", 15 | "width": "col-md-12", 16 | "textdescription": "

Wielki wytuł


" 17 | }, 18 | { 19 | "field": "input", 20 | "type": "text", 21 | "label": "Label input", 22 | "name": "input1", 23 | "placeholder": "place", 24 | "helpBlock": "desc input text", 25 | "width": "col-md-6", 26 | "require": true, 27 | "value": "value1", 28 | "id": "id", 29 | "class": "form-control" 30 | } 31 | ], 32 | [ 33 | { 34 | "field": "radio", 35 | "label": "Label Radio", 36 | "helpBlock": "desc radio", 37 | "name": "radio3", 38 | "width": "col-md-6", 39 | "require": true, 40 | "id": "id", 41 | "class": "form-control", 42 | "items": [ 43 | { 44 | "text": "radio1", 45 | "value": "radio-value1", 46 | "id": "", 47 | "checked": true 48 | }, 49 | { 50 | "text": "radio2", 51 | "value": "radio-value2", 52 | "class": "", 53 | "checked": false 54 | } 55 | ] 56 | }, 57 | { 58 | "field": "checkbox", 59 | "label": "Label Checkbox", 60 | "helpBlock": "desc checkbox", 61 | "name": "checkbox4", 62 | "width": "col-md-6", 63 | "id": "id", 64 | "class": "form-control", 65 | "items": [ 66 | { 67 | "text": "checkbox1", 68 | "value": "checkbox-value1", 69 | "id": "", 70 | "checked": true 71 | }, 72 | { 73 | "text": "checkbox2", 74 | "value": "checkbox-value2", 75 | "class": "", 76 | "checked": false 77 | } 78 | ] 79 | } 80 | ], 81 | [ 82 | { 83 | "field": "select", 84 | "label": "select label", 85 | "name": "field5", 86 | "helpBlock": "desc checkbox", 87 | "width": "col-md-6", 88 | "require": true, 89 | "id": "", 90 | "class": "form-control", 91 | "items": [ 92 | { 93 | "text": "select1", 94 | "value": "select-value1", 95 | "id": "", 96 | "checked": true 97 | }, 98 | { 99 | "text": "select2", 100 | "value": "select-value2", 101 | "class": "", 102 | "checked": false 103 | }, 104 | ] 105 | }, 106 | { 107 | "field": "description", 108 | "textdescription": "

Lorem Ipsum

jest tekstem stosowanym jako przykładowy wypełniacz w przemyśle poligraficznym. Został po raz pierwszy użyty w XV w. przez nieznanego drukarza do wypełnienia tekstem próbnej książki.
Pięć wieków później zaczął być używany przemyśle elektronicznym, pozostając praktycznie niezmienionym.", 109 | "width": "col-md-12", 110 | "id": "id" 111 | } 112 | ], 113 | [ 114 | { 115 | "field": "input", 116 | "name": "field6", 117 | "type": "text", 118 | "width": "col-md-6", 119 | "class": "form-control" 120 | } 121 | ], 122 | [ 123 | { 124 | "field": "submit", 125 | "label": "Submit", 126 | "width": "col-md-6", 127 | "backgroundcolor": "btn-primary" 128 | } 129 | ] 130 | 131 | ] 132 | } 133 | console.log(version); 134 | 135 | if(form){ 136 | form.generate(object_form); 137 | form.deleteField(0, 1) 138 | form.model.body = []; 139 | form.generate(object_form) 140 | form.add(object_form.body[0][0]); 141 | form.add(object_form.body[2][1]); 142 | } 143 | 144 | return null 145 | 146 | }; 147 | -------------------------------------------------------------------------------- /assets/form/js/forms/creator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //#Copyright (c) 2017 Rafal Marguzewicz pceuropa.net 3 | 4 | var MyFORM = MyFORM || {}; 5 | MyFORM = (function(){ 6 | 7 | var hello = 'hello', 8 | version = '1.0', 9 | 10 | Form = function (){ 11 | this.title = "FormBuilder"; 12 | this.action = ""; 13 | this.method = "post"; 14 | this.language = "English"; 15 | this.body = []; 16 | this.get(); 17 | console.log('constructor'); 18 | this.render() 19 | 20 | }; 21 | 22 | 23 | Form.prototype = { 24 | 25 | 26 | constructor: Form, 27 | viewMode: 'html', 28 | map: { index: "0", row: "0" }, 29 | config: {get: true, save: true, autosave: false}, 30 | 31 | 32 | clear: function (o) { 33 | var notReference = {} 34 | for (var prop in o) { 35 | if (o.hasOwnProperty(prop)){ 36 | notReference[prop] = o[prop]; 37 | } 38 | } 39 | return notReference; 40 | }, 41 | filter: function (o){ 42 | var clear = {}; 43 | for (var prop in o){ 44 | if (o[prop]){ 45 | if(Array.isArray(o[prop])){ 46 | clear[prop] = []; 47 | for (var i = o[prop].length; i--;){ 48 | clear[prop][i] = o[prop][i]; 49 | 50 | } 51 | o[prop] = []; 52 | } else { 53 | if(prop !== 'view'){ 54 | clear[prop] = o[prop]; 55 | } 56 | } 57 | } 58 | } 59 | return clear; 60 | }, 61 | 62 | get: function (){ 63 | var form = this; 64 | if(this.config.get){ 65 | $.getJSON(document.URL, function(r){ 66 | console.log('upload from base correct'); 67 | form.generate(r) 68 | }); 69 | } 70 | }, 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | generate: function(o){ 80 | 81 | 82 | this.title = o.title || '';; 83 | this.action = o.action || ''; 84 | this.method = o.method || ''; 85 | this.id = o.id || ''; 86 | this.body['class'] = o['class'] || ''; 87 | this.body = o.body || {}; 88 | if(this.body.length > 0){ 89 | this.render(); 90 | } 91 | }, 92 | 93 | 94 | 95 | 96 | 97 | // <---- View 98 | 99 | 100 | // rows -> row - > fields - > field - > render 101 | 102 | rows: function(){ 103 | var rows = ''; 104 | if(this.body.length == 0) return rows; 105 | for (var i = 0, max = this.body.length; i < max; i += 1){ 106 | rows += this.row(i); 107 | } 108 | return rows; 109 | }, 110 | 111 | row: function(id){ 112 | return '\n
\n'+ this.fields(id) +' \n
\n'; 113 | }, 114 | fields: function(id){ 115 | var fields = ''; 116 | for (var i = 0, max = this.body[id].length; i < max; i++){ 117 | fields += this.field(id, i); 118 | } 119 | return fields; 120 | }, 121 | 122 | field: function(row, index){ 123 | var f = this.body[row][index], 124 | field = new MyFORM.field.factory(f); 125 | 126 | // test ----- console.log(row, index, f.field, Array(20 - f.field.length).join("-"), field); 127 | 128 | 129 | return field.html(); 130 | }, 131 | render: function(){ 132 | var divForm = $("#preview-form"); 133 | console.log('text'); 134 | 135 | switch(Form.prototype.viewMode){ 136 | case 'text': divForm.html('
 
').find('code').text(this.view('html')); break; 137 | case 'json': divForm.html('
 
').find('code').text(this.view('json')); break; 138 | case 'yii2': divForm.html('
 
').find('code').text('Yii2'); break; 139 | default: divForm.html(this.view('html')); break; 140 | } 141 | }, 142 | 143 | view: function (mode){ 144 | switch(mode){ 145 | case 'html': 146 | return '
' + 147 | this.rows() + '\n
';; break; 148 | case 'json': return JSON.stringify(this, null, 4); break; 149 | case 'h1': return this.title; break; 150 | default: null; 151 | } 152 | 153 | }, 154 | 155 | 156 | 157 | 158 | setView: function(view){ 159 | Form.prototype.viewMode = view || ''; 160 | }, 161 | 162 | 163 | 164 | 165 | 166 | }; 167 | 168 | return { 169 | version: version, 170 | Form: Form, 171 | } 172 | 173 | })(); 174 | -------------------------------------------------------------------------------- /assets/form/js/forms/forms.min.js: -------------------------------------------------------------------------------- 1 | //#Copyright (c) 2016-2017 Rafal Marguzewicz pceuropa.net 2 | "use strict";var MyFORM=MyFORM||{};MyFORM=function(){var b="1.0",c=function(){this.title="FormBuilder",this.action="",this.method="post",this.language="English",this.body=[],this.get(),console.log("constructor"),this.render()};return c.prototype={constructor:c,viewMode:"html",map:{index:"0",row:"0"},config:{get:!0,save:!0,autosave:!1},clear:function(a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},filter:function(a){var b={};for(var c in a)if(a[c])if(Array.isArray(a[c])){b[c]=[];for(var d=a[c].length;d--;)b[c][d]=a[c][d];a[c]=[]}else"view"!==c&&(b[c]=a[c]);return b},get:function(){var a=this;this.config.get&&$.getJSON(document.URL,function(b){console.log("upload from base correct"),a.generate(b)})},generate:function(a){this.title=a.title||"",this.action=a.action||"",this.method=a.method||"",this.id=a.id||"",this.body.class=a.class||"",this.body=a.body||{},this.body.length>0&&this.render()},rows:function(){var a="";if(0==this.body.length)return a;for(var b=0,c=this.body.length;b\n'+this.fields(a)+" \n\n"},fields:function(a){for(var b="",c=0,d=this.body[a].length;c ").find("code").text(this.view("html"));break;case"json":a.html("
 
").find("code").text(this.view("json"));break;case"yii2":a.html("
 
").find("code").text("Yii2");break;default:a.html(this.view("html"))}},view:function(a){switch(a){case"html":return'
"+this.rows()+"\n
";case"json":return JSON.stringify(this,null,4);case"h1":return this.title}},setView:function(a){c.prototype.viewMode=a||""}},{version:b,Form:c}}();var MyFORM=MyFORM||{};MyFORM.field=function(){var a=function(a){this.body=a||{},this.init()};a.prototype={constructor:a,view:!0,init:function(){this.set(MyFORM.field[this.body.field])},uiHelper:function(){var a=this;!function(){for(var c=document.getElementById(a.body.field).getElementsByClassName("data-source"),d=0;dPreview field: (html)

"+b.html()):a.html("

Preview field: (text)

 

").find("code").text(b.html()),a.find("a").click(function(){b.view=!b.view,b.render()})},renderUpdateItemField:function(){var a=this;this.body.hasOwnProperty("items")&&this.body.items.length&&$("#"+a.body.field+" .select-item-to-change").html(function(){var b=0,c="",d="";for(b;b'+(b+1)+". "+c+"";return'"}())},is:function(a){return a?a:""},typeAttr:function(){return this.body.type?' type="'+this.body.type+'"':""},labelAttr:function(){var a="";return this.body.require&&(a=" *"),this.body.label?"\n\t":""},nameAttr:function(a){var a=a||!1;return a?this.body.name?' name="'+this.body.name+'[]"':"":this.body.name?' name="'+this.body.name+'"':""},valueAttr:function(){return this.body.value?' value="'+this.body.value+'"':" "},placeholderAttr:function(){return this.body.placeholder?' placeholder="'+this.body.placeholder+'"':""},idAttr:function(){return this.body.id?' id="'+this.body.id+'"':""},classAttr:function(){return this.body.class?' class="form-control '+this.body.class+'"':' class="form-control"'},dataAttr:function(){return this.body.data?' data="'+this.body.data+'"':""},rowsAttr:function(){return this.body.rows?' rows="'+this.body.rows+'"':""},checkedAttr:function(){return this.body.checked?" checked":""},requireAttr:function(){return this.body.require?" required":""},checkedAttr:function(){return this.body.require?" checked":""},helpBlockAttr:function(){return this.body.helpBlock?'\n\t'+this.body.helpBlock+"":""},div:function(){return'
'},divEnd:function(){return"\n
"},attr:function(){for(var a,b="",c=arguments.length,a=0;a"+this.labelEl(b)},editElement:function(a){return Form.prototype.editEl.call(this,a)},glyphicon:function(a,b){return''},deleteItem:function(a){if(!a)throw console.log("Delete item by index:"),a;this.body.items.splice(a,1),this.render()},cloneItem:function(a){if(!a)throw console.log("Clone item by index:"),a;var b=this.body.items[a];this.body.items.splice(a,0,b),this.render()}};var b={html:function(){return this.div()+this.labelAttr()+'\n\t"+this.helpBlockAttr()+this.divEnd()}},c={html:function(){var a=this.value?this.value:"";return this.div()+this.labelAttr()+"\t"+this.helpBlockAttr()+this.divEnd()}},d={html:function(){return this.div()+this.labelAttr()+this.inputs()+this.helpBlockAttr()+this.divEnd()},labelAttr:function(){var a="";return this.body.require&&(a=" *"),this.body.label?"\t

"+this.body.label+a+"

":""},input:function(a){return'\n\t
"}},e={html:function(){return this.div()+this.labelAttr()+this.inputs()+this.helpBlockAttr()+this.divEnd()},input:function(a){return'\n\t
"}},f={html:function(){return this.div()+this.labelAttr()+"\n\t"+this.helpBlockAttr()+this.divEnd()},input:function(a){return"\n\t\t"}},g={classAttr:function(){return this.body.class?" "+this.body.class:""},div:function(){return"
'},html:function(){return this.div()+this.is(this.body.description)+this.divEnd()}},h={html:function(){return this.div()+'\t"+this.divEnd()}};return{factory:a,input:b,textarea:c,radio:d,checkbox:e,select:f,description:g,submit:h}}(); 3 | -------------------------------------------------------------------------------- /assets/form/js/forms/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //#Copyright (c) 2016-2017 Rafal Marguzewicz pceuropa.net 3 | 4 | /* 5 | list of tools: 6 | capitalizeFirstLetter - capitalize first letter of string 7 | clearObject - delete empty variable of object 8 | clone - copy without reference 9 | 10 | each 11 | fibonacci 12 | firstProp 13 | firstValue 14 | getName 15 | getAllProperty 16 | 17 | isString 18 | is 19 | isBoolean 20 | isArray 21 | isObject 22 | 23 | subString 24 | setData 25 | uniqueName 26 | */ 27 | 28 | 29 | 30 | 31 | 32 | var h = { 33 | version: '2.0.1', 34 | /** 35 | * Capitalize First letter of string 36 | * 37 | * @param {String} s 38 | * @return {String} 39 | */ 40 | capitalizeFirstLetter: function (s) { 41 | return s.charAt(0).toUpperCase() + s.slice(1); 42 | }, 43 | 44 | 45 | clearObject: function(o){ 46 | for (var i in o) { 47 | if (o[i] === null || o[i] === undefined) { 48 | delete o[i]; 49 | } 50 | } 51 | return o; 52 | }, 53 | 54 | clone: function (o) { 55 | var clone = {}; 56 | 57 | for (var prop in o) { 58 | 59 | if( this.isArray(o[prop]) ){ 60 | for (var i = 0; i < o[prop].length; i++){ 61 | clone[prop][i] = o[prop][i]; 62 | } 63 | } else { 64 | clone[prop] = o[prop]; 65 | } 66 | } 67 | return clone; 68 | }, 69 | 70 | 71 | 72 | each: function (arr, callback) { 73 | if(this.isArray(arr)){ 74 | var i = 0; 75 | for (i; i < arr.length; i++) { 76 | callback(i, arr[i]); 77 | } 78 | } 79 | 80 | }, 81 | fibonacci: function (n) { 82 | return n < 1 ? 0 : n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2); 83 | }, 84 | firstProp: function (o) { 85 | if(this.isObject(o)){ 86 | return Object.keys(o)[0]; 87 | } else { 88 | return false 89 | } 90 | }, 91 | 92 | firstValue: function (o) { 93 | if( this.isObject(o) ){ 94 | return o[Object.keys(o)[0]]; 95 | } else { 96 | return false 97 | } 98 | }, 99 | 100 | getName: function() { 101 | var 102 | funcNameRegex = /function (.{1,})\(/, 103 | results = (funcNameRegex).exec((this).constructor.toString()); 104 | 105 | return (results && results.length > 1) ? results[1] : ""; 106 | }, 107 | 108 | 109 | getAllProperty: function (prop, o) { 110 | var help = this, result = []; 111 | if(o.length == 0 ) return result; 112 | 113 | help.each(o, function (i, value) { 114 | if( value.length !== 0 || help.isArray(value) ){ 115 | help.each(value, function (j, v) { 116 | 117 | if ( v.hasOwnProperty(prop) ) { 118 | result.push(v[prop]) 119 | } 120 | }); 121 | } 122 | 123 | }); 124 | 125 | return result; 126 | }, 127 | 128 | isString: function(s) { 129 | return typeof s === "string" || s instanceof String 130 | }, 131 | 132 | is: function(v) { 133 | return (v !== null && v !== undefined && v !== '') 134 | }, 135 | 136 | isBoolean: function (v) { 137 | return typeof v === "boolean" 138 | }, 139 | 140 | isArray: function (o) { 141 | if (!Array.isArray) { 142 | return Object.prototype.toString.call(o) === '[object Array]'; 143 | } else { 144 | return Array.isArray(o); 145 | } 146 | }, 147 | 148 | isObject: function (o) { 149 | return typeof o === "object" && this.is(o); 150 | }, 151 | 152 | inheritAll: function (o, inherit) { 153 | for (var prop in inherit) { 154 | if (inherit.hasOwnProperty(prop)){ 155 | o[prop] = inherit[prop]; 156 | } 157 | } 158 | }, 159 | 160 | replaceChars: function (o, char) { 161 | char = char || '_' 162 | return o.replace( new RegExp(/[^A-Za-z0-9w]/, 'g'), char) 163 | }, 164 | 165 | renderSelectUpdateItem: function(field){ 166 | var helpers = this 167 | if(field.body.hasOwnProperty('items')){ 168 | if(field.body.items.length){ 169 | 170 | $("#" + field.body.field + " .select-item-to-change").html( 171 | (function () { 172 | var i = 0, text = '', itemOption = ''; 173 | 174 | for (i; i < field.body.items.length; i++) { 175 | text = field.body.items[i].text ? field.body.items[i].text : ''; 176 | itemOption += ''; 177 | } 178 | return ''; 179 | })() 180 | ); 181 | } else { 182 | $("#" + field.body.field + " .select-item-to-change").empty() 183 | } 184 | 185 | } 186 | }, 187 | 188 | subString: function(str, len) { 189 | len = len || 10 190 | if(str.length > len) str = str.substring(0,len) + '...'; 191 | return str 192 | }, 193 | 194 | setData: function (value) { // set only not empty data 195 | return 196 | }, 197 | setAttribute: function (el, attribute, value) { 198 | if(this.isObject(el) || this.isString(attribute) || this.is(value) ){ 199 | el.setAttribute(attribute, value); 200 | } 201 | }, 202 | 203 | 204 | 205 | uniqueName: function (name, list) { 206 | if( $.inArray(name, list) ){ 207 | name = name + '_2' 208 | } 209 | return name; 210 | }, 211 | 212 | 213 | 214 | }; 215 | 216 | (function($){ 217 | $.fn.extend({ 218 | donetyping: function(callback, timeout){ 219 | 220 | timeout = timeout || 1e3; // 1 second default timeout 221 | 222 | var timeoutReference, 223 | doneTyping = function(el){ 224 | 225 | if (!timeoutReference) return; 226 | timeoutReference = null; 227 | callback.call(el); 228 | }; 229 | 230 | return this.each(function(i,el){ 231 | 232 | $(el).on('keyup paste', function(e){ 233 | 234 | if (timeoutReference) clearTimeout(timeoutReference); // stop timeout 235 | 236 | timeoutReference = setTimeout(function(){ 237 | doneTyping(el); 238 | }, timeout); 239 | 240 | }).on('blur',function(){ 241 | doneTyping(el); 242 | }); 243 | 244 | }); 245 | 246 | 247 | } 248 | }); 249 | })(jQuery); 250 | 251 | -------------------------------------------------------------------------------- /bootstrap/ActiveField.php: -------------------------------------------------------------------------------- 1 | parts['{input}'])) { 30 | $this->textInput(); 31 | } 32 | if (!isset($this->parts['{label}'])) { 33 | $this->label(); 34 | } 35 | if (!isset($this->parts['{error}'])) { 36 | $this->error(); 37 | } 38 | if (!isset($this->parts['{hint}'])) { 39 | $this->hint(null); 40 | } 41 | if (!isset($this->parts['{description}'])) { 42 | $this->description(); 43 | } 44 | 45 | $content = strtr($this->template, $this->parts); 46 | } elseif (!is_string($content)) { 47 | $content = call_user_func($content, $this); 48 | } 49 | 50 | return $this->begin() . "\n" . $content . "\n" . $this->end(); 51 | } 52 | 53 | public function description($options = []) 54 | { 55 | if ($options === false) { 56 | $this->parts['{description}'] = ''; 57 | return $this; 58 | } 59 | 60 | $this->parts['{description}'] = $this->description; 61 | return $this; 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /bootstrap/ActiveForm.php: -------------------------------------------------------------------------------- 1 | $value) { 49 | if (isset($value['checked'])) { 50 | $checked[] = $value['value']; 51 | } 52 | 53 | } 54 | 55 | $items = ArrayHelper::map($field['items'], 'value', 'text'); 56 | $model-> {$field['name']} = $checked; 57 | 58 | if (!isset($field['label'])) { 59 | $options['template'] = "{input}\n{hint}\n{description}\n{error}"; 60 | } 61 | 62 | } 63 | 64 | if (isset($field['helpBlock'])) { 65 | $options['description'] = $field['helpBlock']; 66 | } 67 | 68 | foreach (['placeholder', 'value', 'id', 'class', 'type'] as $key => $value) { 69 | if (isset($field[$value])) { 70 | $options['inputOptions'][$value] = $field[$value]; 71 | } 72 | } 73 | switch ($field['field']) { 74 | case 'input': 75 | $field = parent::field($model, $field['name'], $options)->label($field['label'] ?? false); 76 | break; 77 | case 'textarea': 78 | $field = parent::field($model, $field['name'], $options)->textarea()->label($field['label'] ?? false); 79 | break; 80 | case 'radio': 81 | $field = parent::field($model, $field['name'], $options)->radioList($items)->label($field['label'] ?? false); 82 | break; 83 | case 'checkbox': 84 | $field = parent::field($model, $field['name'], $options)->checkboxList($items)->label($field['label'] ?? false); 85 | break; 86 | case 'select': 87 | $field = parent::field($model, $field['name'], $options)->dropDownList($items)->label($field['label'] ?? false); 88 | break; 89 | case 'description': 90 | $field = self::description($field); 91 | break; 92 | case 'submit': 93 | $field = self::submit($field); 94 | break; 95 | default: 96 | $field = ''; 97 | break; 98 | } 99 | 100 | return self::div($width, $field); 101 | 102 | } 103 | public static function checkbox($form, $model, $field) { 104 | $items = []; 105 | $checked = []; 106 | 107 | foreach ($field['items'] as $key => $value) { 108 | 109 | $items[$value['value']] = $value['text']; 110 | if (isset($value['checked'])) { 111 | $checked[] = $key+1; 112 | } 113 | 114 | } 115 | 116 | $items = ArrayHelper::map($field['items'], 'value', 'text'); 117 | $model-> {$field['name']} = $checked; 118 | $checkbox_list = $form->field($model, $field['name'])->checkboxList($items); 119 | 120 | $label = (isset($field['label'])) ? $field['label'] : ''; 121 | $checkbox_list->label($label); 122 | 123 | return $checkbox_list; 124 | 125 | 126 | 127 | } 128 | /** 129 | * Set items for field list 130 | * 131 | * @param array $field 132 | * @return void 133 | */ 134 | public function setItems(array $field) { 135 | 136 | $items = []; 137 | $checked = []; 138 | 139 | foreach ($field['items'] as $key => $value) { 140 | 141 | $items[$value['value']] = $value['text']; 142 | 143 | if (isset( $value['checked'] )) { 144 | $checked[] = $key+1; 145 | } 146 | } 147 | } 148 | /** 149 | * Generates a label tag for [[attribute]]. 150 | * @param null|string|false $label the label to use. If `null`, the label will be generated via [[Model::getAttributeLabel()]]. 151 | * If `false`, the generated field will not contain the label part. 152 | * Note that this will NOT be [[Html::encode()|encoded]]. 153 | * @param null|array $options the tag options in terms of name-value pairs. It will be merged with [[labelOptions]]. 154 | * The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded 155 | * using [[Html::encode()]]. If a value is `null`, the corresponding attribute will not be rendered. 156 | * @return $this the field object itself. 157 | */ 158 | public function label($label = null, $options = []) 159 | { 160 | echo '
';
161 |         print_r('');
162 |         die();
163 |         if ($label === false) {
164 |             $this->parts['{label}'] = '';
165 |             return $this;
166 |         }
167 | 
168 |         $options = array_merge($this->labelOptions, $options);
169 |         if ($label !== null) {
170 |             $options['label'] = $label;
171 |         }
172 | 
173 |         if ($this->_skipLabelFor) {
174 |             $options['for'] = null;
175 |         }
176 | 
177 |         $this->parts['{label}'] = Html::activeLabel($this->model, $this->attribute, $options);
178 | 
179 |         return $this;
180 |     }
181 | 
182 |     /**
183 |      * Return HTML div with field
184 |      * @param string $width Class bootstrap
185 |      * @param string $field
186 |      * @return string
187 |     */
188 |     public static function div($width, $field) {
189 |         return Html::tag('div', $field, ['class' => $width]);
190 |     }
191 | 
192 |     /**
193 |     * Renders a description html.
194 |     * @param array $v
195 |     * @return string
196 |     */
197 |     public static function description($v) {
198 |         return $v['textdescription'];
199 |     }
200 | 
201 |     /**
202 |       * Renders a submit buton tag.
203 |       * @param array $data
204 |       * @return string The generated submit button tag
205 |       */
206 |     public static function submit($data) {
207 |         return Html::submitButton($data['label'], ['class' => 'btn '.$data['backgroundcolor'] ]);
208 |     }
209 | }
210 | 


--------------------------------------------------------------------------------
/codeception.yml:
--------------------------------------------------------------------------------
 1 | actor: Tester
 2 | paths:
 3 |     tests: tests/php
 4 |     log: tests/php/_output
 5 |     data: tests/php/_data
 6 |     support: tests/php/_support
 7 |     envs: tests/php/_envs
 8 | settings:
 9 |     bootstrap: _bootstrap.php
10 |     colors: true
11 |     memory_limit: 1024M
12 | extensions:
13 |     enabled:
14 |         - Codeception\Extension\RunFailed
15 | modules:
16 |     config:
17 |         Yii2:
18 |             configFile: 'config/test.php'
19 | 


--------------------------------------------------------------------------------
/commands/InitController.php:
--------------------------------------------------------------------------------
  1 | getPermission($permission);
 41 |         } catch (\yii\db\Exception $e) {
 42 |             echo $this->ansiFormat($e->errorInfo[2], Console::FG_RED);echo "\n";
 43 |             echo $this->ansiFormat('Rbac migration:  php yii migrate/up --migrationPath=@yii/rbac/migrations', Console::FG_YELLOW);echo "\n";
 44 |             return false;
 45 | 
 46 |         }
 47 | 
 48 |         if (!($createForm instanceof Permission)) {
 49 |             $createForm = $authManager->createPermission($permission);
 50 |             $createForm->description = 'Create forms';
 51 |             $authManager->add($createForm);
 52 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
 53 |             echo "\n";
 54 |         } else {
 55 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
 56 |             echo "\n";
 57 |         }
 58 | 
 59 |         $permission = self::UPDATE_FORM;
 60 |         $updateForm = $authManager->getPermission($permission);
 61 |         if (!($updateForm instanceof Permission)) {
 62 |             $updateForm = $authManager->createPermission($permission);
 63 |             $updateForm->description = 'update forms';
 64 |             $authManager->add($updateForm);
 65 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN); echo "\n";
 66 |         } else {
 67 |             echo $this->ansiFormat('Permision `'.$permission.'` exist', Console::FG_YELLOW); echo "\n";
 68 |         }
 69 | 
 70 |         $permission = self::DELETE_FORM;
 71 |         $deleteForm = $authManager->getPermission($permission);
 72 |         if (!($deleteForm instanceof Permission)) {
 73 |             $deleteForm = $authManager->createPermission($permission);
 74 |             $deleteForm->description = 'delete forms';
 75 |             $authManager->add($deleteForm);
 76 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
 77 |             echo "\n";
 78 |         } else {
 79 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
 80 |             echo "\n";
 81 |         }
 82 | 
 83 |         $permission = self::VIEWDATA_FORM;
 84 |         $viewdataForm = $authManager->getPermission($permission);
 85 |         if (!($viewdataForm instanceof Permission)) {
 86 | 
 87 |             $viewdataForm = $authManager->createPermission($permission);
 88 |             $viewdataForm->description = 'view data forms';
 89 |             $authManager->add($viewdataForm);
 90 | 
 91 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
 92 |             echo "\n";
 93 |         } else {
 94 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
 95 |             echo "\n";
 96 |         }
 97 | 
 98 |         $role = self::USER;
 99 |         $userForm = $authManager->getRole($role);
100 |         if (!($userForm instanceof role)) {
101 | 
102 |             $userForm = $authManager->createrole($role);
103 |             $userForm->description = 'user role';
104 |             $authManager->add($userForm);
105 | 
106 |             $authManager->addchild($userForm, $createForm);
107 |             $authManager->addchild($userForm, $deleteForm);
108 |             $authManager->addchild($userForm, $updateForm);
109 | 
110 |             echo $this->ansiformat('Role `'.$role .'` added successfully', console::FG_GREEN);
111 |             echo "\n";
112 |         } else {
113 |             echo $this->ansiformat('Role `'.$role .'` exist', console::FG_YELLOW);
114 |             echo "\n";
115 |         }
116 | 
117 |         $rule = new \pceuropa\forms\rbac\AuthorFormRule;	// added successfully the rule
118 |         $updateOwnForm = $authManager->getRule($rule->name);
119 |         if (!($updateOwnForm instanceof Rule)) {
120 |             $authManager->add($rule);
121 | 
122 |             echo $this->ansiFormat('Rule `'.$rule->name .'` added successfully', Console::FG_GREEN);
123 |             echo "\n";
124 |         } else {
125 |             echo $this->ansiFormat('Rule `'.$rule->name .'` exist', Console::FG_YELLOW);
126 | 
127 |             echo "\n";
128 |         }
129 | 
130 | 
131 |         $permission = self::UPDATE_OWN_FORM;
132 |         $updateOwnForm = $authManager->getPermission($permission);
133 |         if (!($updateOwnForm instanceof Permission)) {
134 | 
135 |             // added successfully the "updateOwnForm" permission and associate the rule with it.
136 |             $updateOwnForm = $authManager->createPermission($permission);
137 |             $updateOwnForm->description = 'Update own form';
138 |             $updateOwnForm->ruleName = $rule->name;
139 |             $authManager->add($updateOwnForm);
140 | 
141 |             $authManager->addChild($userForm, $updateOwnForm);
142 | 
143 | 
144 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
145 |             echo "\n";
146 |         } else {
147 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
148 |             echo "\n";
149 |         }
150 | 
151 |         if ($this->confirm("Could you assign role `user` to all users.")) {
152 |             $query = (new Query())->from('user');
153 |             $count = $query->count();
154 |             echo $this->ansiFormat($count .' users in database', Console::FG_RED);
155 |             echo "\n";
156 | 
157 |             $ids = $query->select('id')->all();
158 |             foreach ($ids as $key => $value) {
159 |                 try {
160 | 
161 |                     $authManager->assign($userForm, $value['id']);
162 |                     echo $this->ansiFormat('Assign role `'.$userForm->name.'` to user id: '. $value['id'] , Console::FG_GREEN);
163 |                     echo "\n";
164 |                 } catch (\yii\db\IntegrityException $e) {
165 |                     echo $this->ansiFormat('Not assign role `'.$userForm->name.'` to user id: '. $value['id'].'. Maybe exist' , Console::FG_RED);
166 |                     echo "\n";
167 |                 }
168 |             }
169 |         }
170 |     }
171 | }
172 | ?>
173 | 


--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
 1 | {
 2 | 	"name": "pceuropa/yii2-forms",
 3 | 	"description": "Form builder or code generator for Yii2. List GridView of forms. Saving form data in a databases.",
 4 | 	"keywords": [
 5 | 		"yii2",
 6 | 		"extension",
 7 | 		"form creator",
 8 | 		"form builder",
 9 | 		"drag end drop",
10 | 		"bootstrap form",
11 | 		"without model",
12 | 		"dynamic model"
13 | 	],
14 | 	"homepage": "https://pceuropa.net/yii2-extensions/yii2-forms",
15 | 	"type": "yii2-extension",
16 | 	"license": "MIT",
17 | 	"authors": [
18 | 		{
19 | 		  "name": "Rafal Marguzewicz",
20 | 		  "email": "info@pceuropa.net",
21 | 		  "homepage": "https://pceuropa.net/"
22 | 		}
23 | 	],
24 | 	"require": {
25 |     "php": ">=7.0.0",
26 | 		"yiisoft/yii2": "^2.0",
27 | 		"pceuropa/yii2-email": "*"
28 | 	},
29 | 	"autoload": {
30 | 		"psr-4": {
31 | 		  "pceuropa\\forms\\": ""
32 | 		}
33 | 	}
34 | }
35 | 


--------------------------------------------------------------------------------
/config/params.php:
--------------------------------------------------------------------------------
1 |  'admin@example.com',
5 | ];
6 | 


--------------------------------------------------------------------------------
/config/test.php:
--------------------------------------------------------------------------------
 1 |  'basic-tests',
 9 |     'basePath' => dirname(__DIR__),    
10 |     'language' => 'en-US',
11 |     'components' => [
12 |         'db' => [
13 |             'class' => 'yii\db\Connection',
14 |             'dsn' => 'mysql:host=localhost;dbname=yii2_basic_tests',
15 |             'username' => 'root',
16 |             'password' => '',
17 |             'charset' => 'utf8',
18 |         ],
19 |         'mailer' => [
20 |             'useFileTransport' => true,
21 |         ],
22 |         'urlManager' => [
23 |             'showScriptName' => true,
24 |         ],
25 |         'user' => [
26 |             'identityClass' => 'app\models\User',
27 |         ],        
28 |         'request' => [
29 |             'cookieValidationKey' => 'test',
30 |             'enableCsrfValidation' => false,
31 |             // but if you absolutely need it set cookie domain to localhost
32 |             /*
33 |             'csrfCookie' => [
34 |                 'domain' => 'localhost',
35 |             ],
36 |             */
37 |         ],        
38 |     ],
39 |     'params' => $params,
40 | ];
41 | 


--------------------------------------------------------------------------------
/config/test_db.php:
--------------------------------------------------------------------------------
1 |  'Form budowniczy',  
  7 |     'All forms' => 'Wszystkie formularze',
  8 |     'Form' => 'Formularz',  
  9 |     'Forms' => 'Formularze',  
 10 |     'Your forms' => 'Twoje formularze',  
 11 |     'Create' => 'Stwórz',  
 12 |     'Field' => 'Pole',  
 13 |     'Input' => 'Pole tekstowe',  
 14 |     'TextArea' => 'Pole tekstowe wieloliniowe',  
 15 |     'Radio' => 'Pole jednokrotnego wyboru (radio)',  
 16 |     'Checkbox' => 'Pole wielokrotnego wyboru',  
 17 |     'Select' => 'Pole jednokrotnego wybory (select)',  
 18 |     'Description' => 'Opis',  
 19 |     'Submit Button' => 'Guzik zatwierdź',
 20 |       
 21 |     'View' => 'Widok',  
 22 |     'Title' => 'Tytuł',  
 23 |     'Text' => 'Tekst',  
 24 |     'Save Form' => 'Zapisz formularz',  
 25 |     'Name' => 'Nazwa',  
 26 |     'Type' => 'Typ',  
 27 |     'Limit Entries' => 'Limit',  
 28 |     'Start' => 'Aktywy od',  
 29 |     'End' => 'Aktywy do',  
 30 |     'Type' => 'Typ',  
 31 |     
 32 |     'text' => 'tekst',
 33 |     'URL' => 'Adres URL',
 34 |     'Address URL' => 'Adres URL',
 35 |     'Answers' => 'Odpowiedzi',
 36 |     'email' => 'email',
 37 |     'password' => 'hasło',
 38 |     'date' => 'data',
 39 |     'number' => 'liczba',
 40 |     'phone' => 'telefon',
 41 |     'color' => 'kolor',
 42 |     'range' => 'zakres',
 43 |     'Edit form' => 'Edytuj formularz',
 44 |     'View form' => 'Zobacz formularz',
 45 |     'Delete form' => 'Skasuj',
 46 |     'Completed forms' => 'Wypełnione formularze',
 47 |     
 48 |     'Label' => 'Etykieta',  
 49 |     'Placeholder' => 'Tekst zastępczy',  
 50 |     'Width' => 'Szerokość',  
 51 |     'Value' => 'Tekst domyślny',  
 52 |     'Value item' => 'Wartość',  
 53 |     'Field require' => 'wymagane',  
 54 |     'Rows' => 'Ilość wierszy',  
 55 |     'Add to form' => 'Dodaj do formularza',  
 56 |     'Add item' => 'Dodaj do pola',  
 57 |     'Items' => 'Opcje wyboru',  
 58 |     'Checked' => 'Zaznaczone',  
 59 |     'Selected' => 'Domyślnie wybrany',  
 60 |     'Method' => 'Metoda wysyłki',  
 61 |     'Action' => 'Adres odbioru żądania',  
 62 |     'ID' => 'Html Id',  
 63 |     'Class' => 'Html Class',  
 64 |     'Template' => 'Szablon',  
 65 |     
 66 |     'Preview field' => 'Podgląd pola',  
 67 |     'Preview form' => 'Podgląd formularza',  
 68 |     'Form completed' => 'Formularz wypełniony poprawnie',  
 69 |     
 70 | // manual   
 71 |     'Manual' => 'Podręcznik',  
 72 |     'Form options (right column)' => 'Opcje formularza (kolumna prawa)',  
 73 |     'View changes the color of a displayed code' => 'Widok zmienia rodzaj wyświetlanego kodu',  
 74 |     'Title does not appear in a form code, is used for differentiation in a list of forms. If you need a title, use Field -> Description' => 'Tytuł nie pojawia się w kodzie formularza, służy do rozróżnienia w liście formularzy. Jeżeli potrzebujesz tytułu skorzystaj z Pole -> Opis',  
 75 |     'URL address the URL address of a form' => 'Adres URL adres URL formularza',  
 76 |     'Method (HTTP) a way of data transmission between a form and a collection address' => 'Metoda wysyłki sposób przekazywania danych pomiędzy formularzem a adresem odbioru',  
 77 |     'Action leave blank if the URL collection address is the same as the address of a form' => 'Adres odbioru zostaw puste jeżeli adres URL odbioru jest taki sam jak adres formularza ',  
 78 |     'ID allows setting an id attribute for a form, practicable for CSS' => 'ID pozwala ustawić atrybut id dla formularza, przydatne do CSS',  
 79 |     'Class allows setting a class attribute for a form, practicable for CSS' => 'Class pozwala ustawić atrybut class dla formularza, przydatne do CSS',  
 80 |     'Save the form an option for saving a form which is active upon filling the title and URL address fields' => 'Zapisz formularz opcja zapisania formularza aktywna po wypełnieniu pól tytuł i adres URL',  
 81 |     
 82 |     'Field options' => 'Opcje pola',  
 83 |     'Selection menu allows to choose a particular element' => 'Menu wyboru pozwala wybrać dany element',  
 84 |     'Name an attribute not visible in the form, required for differentiation of received data from filled forms' => 'Nazwa atrybut nie widoczny w formularzu, potrzebny do rozróżnienia otrzymywanych danych z wypełnionych danych',  
 85 |     'Label a writing appearing above a field' => 'Etykieta napis pojawiający się nad polem',  
 86 |     'Placeholder tekst a description of a form field, localized in the field that disappears after you have started to fill in a given field' => 'Tekst zastępczy opis pola formularza, ulokowany w polu, który znika po rozpoczęciu wypełniania danego pola formularza',  
 87 |     'Default text a field filled in automatically' => 'Tekst domyślny domyślnie wypełnione pole',  
 88 |     'Description a descriptive text localized above a field' => 'Opis tekst opisowy ulokowany pod polem',  
 89 |     'Width a field may be of e.g. 50% width and then 2 fields may appear on a computer screen in a line. The field on a smart phone screen is always of 100% width' => 'Szerokość pole może mieć szerokość np 50% w tedy na ekranie komputera mogą być 2 pola w jednej linii. Na ekranie smartfona pole zawsze ma szerokość 100% ',  
 90 |     'Required a form field must be filled in' => 'Wymagane pole formularza musi być uzupełnione',  
 91 |     'ID allows setting an id attribute for a form, practicable for CSS' => 'ID pozwala ustawić atrybut id dla formularza, przydatne do CSS',  
 92 |     'Class allows setting a class attribute for a form, practicable for CSS' => 'Class pozwala ustawić atrybut class dla formularza, przydatne do CSS',  
 93 |     
 94 |     'Field elements in case of multiple choice fields' => 'Elementy pola w przypadku pól wielokrotnego wyboru',  
 95 |     'Text text of one element from a field list' => 'Text tekst jednego elementu z listy pola',  
 96 |     'Value will allow the differentiation of answers, leave blank if you are not sure, the system will paginate automatically' => 'Wartość pozwoli rozróżnić odpowiedzi, zostaw puste jeżeli niemasz pewności, system ponumeruje automatycznie',  
 97 |     'Checked an element of a field list selected automatically' => 'Zaznaczone element listy pola domyślnie wybrany',  
 98 |     
 99 |     'This application allows to easily create Internet forms which may then be made available to be filled in by others. Such generated form allows to versify entered data and record them in a data base or a spreadsheet.' => 'Aplikacja pozwala tworzyć łatwo formularze internetowe,  które następnie możesz udostępniać innym do wypełniania. Tak wygenerowany formularz pozwala na wersyfikację wpisywanych danych oraz zapisywanie ich w bazie danych lub arkuszu kalkulacyjnym.',  
100 |     'You may also generate only a form code (html, yii2, json) and embed it into your application or website. By means of the “form builder” you can create contact and login forms, surveys and many others. ' => 'Możesz również generować jedynie kod formularza( html, yii2, json) i osadzić go w twojej aplikacji lub stronie www. Za pomocą „form budowniczy” możesz tworzyć formularze kontaktowe, logowania, ankiety i wiele innych.',  
101 |     '' => '',  
102 |    
103 | ];
104 | 
105 | 


--------------------------------------------------------------------------------
/migrations/RbacController.php:
--------------------------------------------------------------------------------
  1 | getPermission($permission);
 46 |         } catch (\yii\db\Exception $e) {
 47 |             echo $this->ansiFormat($e->errorInfo[2], Console::FG_RED);
 48 |             echo "\n";
 49 |             echo $this->ansiFormat('Rbac migration:  php yii migrate/up --migrationPath=@yii/rbac/migrations', Console::FG_YELLOW);
 50 |             echo "\n";
 51 |             return false;
 52 | 
 53 |         }
 54 | 
 55 |         if (!($createForm instanceof Permission)) {
 56 |             $createForm = $authManager->createPermission($permission);
 57 |             $createForm->description = 'Create forms';
 58 |             $authManager->add($createForm);
 59 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
 60 |             echo "\n";
 61 |         } else {
 62 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
 63 |             echo "\n";
 64 |         }
 65 | 
 66 |         $permission = self::UPDATE_FORM;
 67 |         $updateForm = $authManager->getPermission($permission);
 68 |         if (!($updateForm instanceof Permission)) {
 69 |             $updateForm = $authManager->createPermission($permission);
 70 |             $updateForm->description = 'update forms';
 71 |             $authManager->add($updateForm);
 72 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
 73 |             echo "\n";
 74 |         } else {
 75 |             echo $this->ansiFormat('Permision `'.$permission.'` exist', Console::FG_YELLOW);
 76 |             echo "\n";
 77 |         }
 78 | 
 79 |         $permission = self::DELETE_FORM;
 80 |         $deleteForm = $authManager->getPermission($permission);
 81 |         if (!($deleteForm instanceof Permission)) {
 82 |             $deleteForm = $authManager->createPermission($permission);
 83 |             $deleteForm->description = 'delete forms';
 84 |             $authManager->add($deleteForm);
 85 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
 86 |             echo "\n";
 87 |         } else {
 88 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
 89 |             echo "\n";
 90 |         }
 91 | 
 92 |         $permission = self::VIEWDATA_FORM;
 93 |         $viewdataForm = $authManager->getPermission($permission);
 94 |         if (!($viewdataForm instanceof Permission)) {
 95 | 
 96 |             $viewdataForm = $authManager->createPermission($permission);
 97 |             $viewdataForm->description = 'view data forms';
 98 |             $authManager->add($viewdataForm);
 99 | 
100 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
101 |             echo "\n";
102 |         } else {
103 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
104 |             echo "\n";
105 |         }
106 | 
107 |         $role = self::USER;
108 |         $userForm = $authManager->getRole($role);
109 |         if (!($userForm instanceof role)) {
110 | 
111 |             $userForm = $authManager->createrole($role);
112 |             $userForm->description = 'user role';
113 |             $authManager->add($userForm);
114 | 
115 |             $authManager->addchild($userForm, $createForm);
116 |             $authManager->addchild($userForm, $deleteForm);
117 |             $authManager->addchild($userForm, $updateForm);
118 | 
119 |             echo $this->ansiformat('Role `'.$role .'` added successfully', console::FG_GREEN);
120 |             echo "\n";
121 |         } else {
122 |             echo $this->ansiformat('Role `'.$role .'` exist', console::FG_YELLOW);
123 |             echo "\n";
124 |         }
125 | 
126 |         $rule = new \pceuropa\forms\rbac\AuthorFormRule;	// added successfully the rule
127 |         $updateOwnForm = $authManager->getRule($rule->name);
128 |         if (!($updateOwnForm instanceof Rule)) {
129 |             $authManager->add($rule);
130 | 
131 |             echo $this->ansiFormat('Rule `'.$rule->name .'` added successfully', Console::FG_GREEN);
132 |             echo "\n";
133 |         } else {
134 |             echo $this->ansiFormat('Rule `'.$rule->name .'` exist', Console::FG_YELLOW);
135 | 
136 |             echo "\n";
137 |         }
138 | 
139 | 
140 |         $permission = self::UPDATE_OWN_FORM;
141 |         $updateOwnForm = $authManager->getPermission($permission);
142 |         if (!($updateOwnForm instanceof Permission)) {
143 | 
144 |             // added successfully the "updateOwnForm" permission and associate the rule with it.
145 |             $updateOwnForm = $authManager->createPermission($permission);
146 |             $updateOwnForm->description = 'Update own form';
147 |             $updateOwnForm->ruleName = $rule->name;
148 |             $authManager->add($updateOwnForm);
149 | 
150 |             $authManager->addChild($userForm, $updateOwnForm);
151 | 
152 | 
153 |             echo $this->ansiFormat('Permision `'.$permission .'` added successfully', Console::FG_GREEN);
154 |             echo "\n";
155 |         } else {
156 |             echo $this->ansiFormat('Permision `'.$permission .'` exist', Console::FG_YELLOW);
157 |             echo "\n";
158 |         }
159 | 
160 |         if ($this->confirm("Could you assign roles to all users.")) {
161 |             $query = (new Query())->from('user');
162 |             $count = $query->count();
163 |             echo $this->ansiFormat($count .' users in database', Console::FG_RED);
164 |             echo "\n";
165 | 
166 |             $ids = $query->select('id')->all();
167 |             foreach ($ids as $key => $value) {
168 |                 try {
169 | 
170 |                     $authManager->assign($userForm, $value['id']);
171 |                     echo $this->ansiFormat('Assign role `'.$userForm->name.'` to user id: '. $value['id'] , Console::FG_GREEN);
172 |                     echo "\n";
173 |                 } catch (\yii\db\IntegrityException $e) {
174 |                     echo $this->ansiFormat('Not assign role `'.$userForm->name.'` to user id: '. $value['id'].'. Maybe exist' , Console::FG_RED);
175 |                     echo "\n";
176 |                 }
177 |             }
178 |         }
179 |     }
180 | }
181 | ?>
182 | 
183 | 
184 | 
185 | 
186 | 
187 | 


--------------------------------------------------------------------------------
/migrations/forms.sql:
--------------------------------------------------------------------------------
 1 | -- phpMyAdmin SQL Dump
 2 | -- version 4.2.12deb2+deb8u2
 3 | -- http://www.phpmyadmin.net
 4 | --
 5 | 
 6 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
 7 | SET time_zone = "+00:00";
 8 | 
 9 | 
10 | CREATE TABLE IF NOT EXISTS `forms` (
11 | `form_id` int(11) NOT NULL,
12 |   `body` text,
13 |   `title` varchar(255) NOT NULL,
14 |   `author` varchar(255) DEFAULT NULL,
15 |   `date_start` datetime DEFAULT NULL,
16 |   `date_end` datetime DEFAULT NULL,
17 |   `maximum` int(11) DEFAULT NULL,
18 |   `meta_title` varchar(255) DEFAULT NULL,
19 |   `url` varchar(255) NOT NULL,
20 |   `response` text
21 | ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
22 | 
23 | ALTER TABLE `forms` ADD PRIMARY KEY (`form_id`), ADD UNIQUE KEY `url-unique` (`url`);
24 | ALTER TABLE `forms` MODIFY `form_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=1;
25 | 


--------------------------------------------------------------------------------
/migrations/m170101_000000_create_form_table.php:
--------------------------------------------------------------------------------
 1 | db->driverName === 'mysql') {
15 |             $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
16 |         }
17 | 
18 |         $this->createTable('{{%forms}}', [
19 |             'form_id' => $this->primaryKey(),
20 |             'body' => $this->text()->notNull(),
21 |             'title' => $this->string(255)->notNull(),
22 |             'author' => $this->integer(11),
23 |             'date_start' => $this->date(),
24 |             'date_end' => $this->dateTime(),
25 |             'maximum' => $this->integer(11)->comment('answers'),
26 |             'meta_title' => $this->string(255),
27 |             'url' => $this->string(255)->notNull(),
28 |             'response' => $this->text()->comment('by email'),
29 |             'answer' => $this->integer(11)->notNull()->defaultValue('0'),
30 |             'action' => $this->string(255),
31 |             'method' => $this->string(4)->defaultValue('post'),
32 |             'language' => $this->string(11)->defaultValue('en'),
33 |             'class' => $this->string(255)->Null()->comment('html'),
34 |             'id' => $this->string(255)->Null()->comment('html'),
35 |             'only_once' => $this->tinyInteger(1)->unsigned()->notNull()->defaultValue('1')->comment('Can be completed only once'),
36 |         ], $tableOptions);
37 | 
38 |         $this->createIndex('url', '{{%forms}}', 'url', true);
39 |     }
40 |     public function safeDown()
41 |     {
42 |         $this->dropTable('{{%forms}}');
43 |     }
44 | }
45 | 


--------------------------------------------------------------------------------
/migrations/m180101_000000_create_user_table.php:
--------------------------------------------------------------------------------
 1 | db->driverName === 'mysql' ? 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB' : null;
15 | 
16 |         $this->createTable('{{%user}}', [
17 |             'id' => Schema::TYPE_PK,
18 |             'username' => Schema::TYPE_STRING . ' NOT NULL',
19 |             'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL',
20 |             'password_hash' => Schema::TYPE_STRING . ' NOT NULL',
21 |             'password_reset_token' => Schema::TYPE_STRING,
22 |             'email' => Schema::TYPE_STRING . ' NOT NULL',
23 |             'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
24 | 
25 |             'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
26 |             'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
27 |             'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
28 |         ], $tableOptions);
29 |     }
30 | 
31 |     public function down(){
32 | 
33 |         $this->dropTable('{{%user}}');
34 |     }
35 | }
36 | 


--------------------------------------------------------------------------------
/models/DynamicFormModel.php:
--------------------------------------------------------------------------------
 1 | get(Module::getInstance()->db);
23 |         } 
24 | 
25 |         return Yii::$app->db;
26 |     }
27 | 
28 | 
29 |     /**
30 |     * Create or clone table
31 |     *
32 |     * @param string $table_name Name of table
33 |     * @param array $table_schema List of columns and types thus
34 |     *
35 |     */
36 |     public function createTable(string $table_name, array $table_schema)
37 |     {
38 |         $db = $this->getDb();
39 |         $command = $db->createCommand();
40 |         $tableOptions = null;
41 |         if ($db->driverName === 'mysql') {
42 |             $tableOptions = 'CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB';
43 |         }
44 | 
45 |         $query = $command->createTable($table_name, array_merge([
46 |             'id' => $this->primaryKey() ?? 'pk',
47 |             '_ip' => $this->string(15),
48 |             '_csrf' => $this->char(88),
49 |             '_user_agent' => $this->string(),
50 |             '_same_site' => $this->string(),
51 |             '_finger_print' => $this->string(),
52 |             '_number_fraud' => $this->tinyInteger()->unsigned()->notNull()->defaultValue('0'),
53 |             '_form_created' => $this->dateTime()->notNull(),
54 |             '_datetime_response' => $this->dateTime()->notNull()->defaultExpression('CURRENT_TIMESTAMP'),
55 |         ], $table_schema), $tableOptions);
56 | 
57 |         if ($query->execute($query)) {
58 |             $command->createIndex('finger_print', $table_name, '_finger_print', true)->execute();
59 |             $command->createIndex('csrf', $table_name, '_csrf', true)->execute();
60 |         }
61 |     }
62 | }
63 | 


--------------------------------------------------------------------------------
/models/FormModel.php:
--------------------------------------------------------------------------------
  1 | 
 12 |  * @version 3.0.2
 13 |  * @license MIT
 14 |  * https://github.com/pceuropa/yii2-forum
 15 |  * Please report all issues at GitHub
 16 |  * https://github.com/pceuropa/yii2-forum/issues
 17 |  *
 18 |  */
 19 | class FormModel extends \yii\db\ActiveRecord {
 20 | 
 21 |     /**
 22 |      * @var boolean Form can be complated only once by one human
 23 |      */
 24 |     public $canByCompletedOnlyOnce = true;
 25 | 
 26 |     /**
 27 |      * @ingeritdoc
 28 |      */
 29 |     public static function getDb() {
 30 | 
 31 |         if (Module::getInstance()) {
 32 |             return Yii::$app->get(Module::getInstance()->db);
 33 |         } else {
 34 |             return Yii::$app->db;
 35 |         }
 36 |     }
 37 | 
 38 |     /**
 39 |      * @ingeritdoc
 40 |      */
 41 |     public static function tableName() {
 42 | 
 43 |         if (Module::getInstance()) {
 44 |             return Module::getInstance()->formTable;
 45 |         } else {
 46 |             return 'forms';
 47 |         }
 48 |     }
 49 | 
 50 |     /**
 51 |      * @ingeritdoc
 52 |      */
 53 |     public function rules() : array
 54 |     {
 55 |         return [
 56 |             [['body', 'title', 'url'], 'required'],
 57 |             [['body', 'response'], 'string'],
 58 |             [['date_start', 'date_end'], 'safe'],
 59 |             [['date_start'], 'default', 'value' => date('Y-m-d')],
 60 |             [['form_id','maximum', 'answer', 'author'], 'integer'],
 61 |             [['only_once'], 'integer', 'max' => 1],
 62 |             [['method'], 'string', 'max' => 4],
 63 |             [['language'], 'string', 'max' => 11],
 64 |             [['title',  'meta_title', 'url', 'id', 'class', 'action'], 'string', 'max' => 255],
 65 |             [['action'], 'default', 'value' => 'POST'],
 66 |             [['url'], 'unique'],
 67 |         ];
 68 |     }
 69 | 
 70 |     /**
 71 |      * @ingeritdoc
 72 |      */
 73 |     public function attributeLabels() : array
 74 |     {
 75 |         return [
 76 |             'form_id' => Yii::t('builder', 'ID'),        //form_id - id for database
 77 |             'author' => Yii::t('builder', 'Author'),
 78 |             'title' => Yii::t('builder', 'Title'),
 79 |             'body' => Yii::t('builder', 'Body'),
 80 |             'date_start' => Yii::t('builder', 'Date'),
 81 |             'answer' => Yii::t('builder', 'Answers'),
 82 |             'date_end' => Yii::t('builder', 'End'),
 83 |             'only_once' => Yii::t('builder', 'Can be completed only once'),
 84 |             'maximum' => Yii::t('builder', 'Max'),
 85 |             'meta_title' => Yii::t('builder', 'Meta Title'),
 86 |             'url' => Yii::t('builder', 'URL'),
 87 |             'id' => Yii::t('builder', 'id'),             // id - for html
 88 |             'class' => Yii::t('builder', 'class'),       // class - for html
 89 |         ];
 90 |     }
 91 |     /**
 92 |      * Unique URL
 93 |      * @param $array form
 94 |      * @return void
 95 |      */
 96 |     public function setUniqueUrl() {
 97 |         do {
 98 |             $this->url .= '_2';
 99 |             $count = FormModel::find()->select(['url'])->where(['url' => $this->url])->count();
100 |         } while ($count > 0);
101 |     }
102 | 
103 |     /**
104 |      * Get form by id number (form_id) in database
105 |      * @param int $id number of form
106 |      * @return array|boolean The first row of the query result represent one form. False is reurned if the query results in nothing
107 |      */
108 |     public static function cloneModel(int $id) {
109 | 
110 |         $form = self::find()
111 |             ->select(['body', 'title', 'author', 'date_start', 'date_end', 'maximum', 'meta_title', 'url', 'response', 'class', 'id', 'only_once'])
112 |             ->where(['form_id' => $id])
113 |             ->asArray()
114 |             ->one();
115 | 
116 |         $new_form = new FormModel();
117 |         foreach ($form as $key => $value) {
118 |             $new_form->{$key} = $value;
119 |         }
120 |         $new_form->setUniqueUrl();
121 |         if ($new_form->save()) {
122 |             return $new_form;
123 |         } else {
124 |             return $new_form->getFirstErrors();
125 |         }
126 |     }
127 | 
128 |     /**
129 |      * Get form by id number (form_id) in database
130 |      * @param int $id number of form
131 |      * @return array|boolean The first row of the query result represent one form. False is reurned if the query results in nothing
132 |      */
133 |     public static function findModel(int $id) {
134 | 
135 |         if (($model = self::find()->where(['form_id' => $id])->one()) !== null ) {
136 |             return $model;
137 |         } else {
138 |             throw new NotFoundHttpException('The requested form does not exist.');
139 |         }
140 |     }
141 | 
142 |     /**
143 |      * Get form by url
144 |      * @param string $url Unique string represent url of form
145 |      * @return array|boolean The first row of the query result represent one form. False is reurned if the query results in nothing
146 |      */
147 |     public function findModelByUrl(string $url) {
148 |         if (($model = self::find()->where(['url' => $url])->one()) !== null) {
149 |             return $model;
150 |         } else {
151 |             throw new NotFoundHttpException('The requested page does not exist.');
152 |         }
153 |     }
154 | 
155 |     /**
156 |      * End registration form
157 |      * @return void
158 |      */
159 |     public function endForm() : bool
160 |     {
161 |         if (is_null($this->maximum) && is_null($this->date_end) ) {
162 |             return false;
163 |         }
164 | 
165 |         // deadline after now
166 |         if (!is_null($this->date_end) && strtotime($this->date_end) < time()) {
167 |             return true;
168 |         }
169 | 
170 |         // is max possible answer is less than answer then end form
171 |         if (!is_null($this->maximum) && $this->maximum <= $this->answer) {
172 |             return true;
173 |         }
174 | 
175 |         return false;
176 |     }
177 | 
178 |     /**
179 |      * End registration form
180 |      * @return void
181 |      */
182 |     private function possibleAnswers()
183 |     {
184 |         $tmp_array = [];
185 |         if (!is_array($this->body)) {
186 |             $this->body = Json::decode($this->body);
187 |         }
188 |         
189 |         foreach(FormBase::onlyCorrectDataFields($this->body) as $key => $field) {
190 |             if (in_array($field['field'], ['radio', 'select', 'checkbox'])) {
191 |                 $tmp_array[$field['name']] = ArrayHelper::getColumn($field['items'], 'value');
192 |             }
193 |         }
194 |         return $tmp_array;
195 |     }
196 | 
197 |     /**
198 |      * Check the correctness of the data
199 |      *
200 |      * Return number of froud
201 |      *
202 |      * @return int
203 |      */
204 |     public function checkCorrectnessData(array $data) : int
205 |     {
206 |         $bad = 0;
207 |         foreach ($this->possibleAnswers() as $key => $value) {
208 | 
209 |             // test checkbox
210 |             if (is_array($data[$key])) {
211 |                 $bad += (int) array_diff($data[$key], $value);
212 |                 continue;
213 |             }
214 |           
215 |             // test radio and select
216 |             if (!in_array($data[$key], $value) and $data[$key] != null) {
217 |                 $bad += 1;
218 |             }
219 |         }
220 |         return $bad;
221 |     }
222 | 
223 |     /**
224 |      * Send only once
225 |      *
226 |      * Protected against send twice
227 |      */
228 |     public function isFormSentOnlyOnce(string $form_id): bool
229 |     {
230 |         if ((bool) $this->only_once) {
231 |             return 
232 |                 Yii::$app->request->cookies->getValue($form_id, null) ?? 
233 |                 Yii::$app->session->get($form_id) ?? 
234 |                 false;
235 |         }
236 |         return false;
237 |     }
238 | }
239 | 


--------------------------------------------------------------------------------
/models/FormModelSearch.php:
--------------------------------------------------------------------------------
 1 | 
12 |  * @version 1.4.1
13 |  * @license MIT
14 |  *
15 |  * https://github.com/pceuropa/yii2-forum
16 |  * Please report all issues at GitHub
17 |  * https://github.com/pceuropa/yii2-forum/issues
18 |  *
19 |  */
20 | class FormModelSearch extends FormModel {
21 | 
22 |     public function rules() : array
23 |     {
24 |         return [
25 |             [['form_id', 'maximum', 'answer'], 'integer'],
26 |             [['author', 'title', 'body', 'date_start', 'date_end', 'meta_title', 'url'], 'safe'],
27 |         ];
28 |     }
29 | 
30 | /**
31 |  * Search and filter result of gridview
32 |  *
33 |  * @param array $param List of params
34 |  * @return ActiveDataProvider 
35 | */
36 |     public function search($params) {
37 |         $query = FormModel::find();
38 |         // add conditions that should always apply here
39 | 
40 |         $dataProvider = new ActiveDataProvider([ 'query' => $query, ]);
41 |         $this->load($params);
42 | 
43 |         if (!$this->validate()) {
44 |             // uncomment the following line if you do not want to return any records when validation fails
45 |             // $query->where('0=1');
46 |             return $dataProvider;
47 |         }
48 | 
49 |         // grid filtering conditions
50 |         $query->andFilterWhere([
51 |             'author' => $this->author,
52 |             'form_id' => $this->form_id,
53 |             'date_start' => $this->date_start,
54 |             'date_end' => $this->date_end,
55 |             'maximum' => $this->maximum,
56 |             'answer' => $this->answer,
57 |         ]);
58 | 
59 |         $query->andFilterWhere(['like', 'title', $this->title])
60 |             ->andFilterWhere(['like', 'body', $this->body])
61 |             ->andFilterWhere(['like', 'meta_title', $this->meta_title])
62 |             ->andFilterWhere(['like', 'url', $this->url]);
63 | 
64 |         return $dataProvider;
65 |     }
66 | }
67 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "yii2-forms-tests",
 3 |   "version": "3.0.2",
 4 |   "description": "Depencies necessary to run tests",
 5 |   "main": "karma.conf.js",
 6 |   "directories": {
 7 |     "test": "tests"
 8 |   },
 9 |   "dependencies": {
10 |     "jasmine-core": "^3.1.0",
11 |     "karma": "^2.0.2",
12 |     "karma-firefox-launcher": "^1.1.0",
13 |     "karma-jasmine": "^1.1.2",
14 |     "karma-phantomjs-launcher": "^1.0.4"
15 |   },
16 |   "devDependencies": {},
17 |   "scripts": {
18 |     "test": "./node_modules/karma/bin/karma start"
19 |   },
20 |   "keywords": [
21 |     "tests"
22 |   ],
23 |   "author": "Rafal Marguzewicz",
24 |   "license": "MIT"
25 | }
26 | 


--------------------------------------------------------------------------------
/rbac/AuthorFormRule.php:
--------------------------------------------------------------------------------
 1 | request->get('id');
25 |         $query = (new Query)->select('author')->where(['form_id' => $id])->from(Module::getInstance()->formTable)->one();
26 |         return $query['author'] == $user;
27 |     }
28 | }
29 | 
30 | 


--------------------------------------------------------------------------------
/tests/helpers.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 
 5 |      
 8 | 
 9 | 
10 | JavaScript Singleton
11 | 
12 | 
13 | 
14 | 
15 | 
16 | 
17 | 
36 | 
37 | 
38 | 
39 | 


--------------------------------------------------------------------------------
/tests/js/SpecRunner.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |   Form Test
 7 |   
 8 |   
 9 | 
10 |   
11 |   
12 |   
13 |   
14 |   
15 |   
16 | 
17 | 
18 | 
19 | 
20 | 
21 | 
22 | 
23 | 
24 | 
25 | 
26 | 
27 | 
28 | 
29 | 
30 | 
31 | 
32 | 
33 |  
34 | 
35 | 


--------------------------------------------------------------------------------
/tests/js/fieldTest.js:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | describe("Test field: input", function() {
  4 | 
  5 | var input = {
  6 |                 "field": "input",
  7 |                 "type": "text",
  8 |                 "width": "col-md-12",
  9 |                 "name": "name",
 10 |                 "label": "label",
 11 |                 "value": "value",
 12 |                 "require": true
 13 |             },
 14 | field_outerHTML = '
', 15 | field_input = new MyFORM.field.factory(input), 16 | field = field_input.html(); 17 | 18 | it("check htmlElement - input", function() { 19 | expect(field.className).toBe("form-group col-md-12"); 20 | expect(field.firstChild.localName).toBe("label"); 21 | expect(field.childElementCount).toBe(2); 22 | expect(field.outerHTML).toBe(field_outerHTML) 23 | }); 24 | 25 | 26 | }) 27 | 28 | describe("Test field: textarea", function() { 29 | 30 | var data = { 31 | "field": "textarea", 32 | "width": "col-md-12", 33 | "name": "name", 34 | "label": "label", 35 | "value": "value", 36 | "require": true, 37 | "helpBlock": "description" 38 | }, 39 | field_input = new MyFORM.field.factory(data), 40 | field_outerHTML = '
description
', 41 | field = field_input.html(); 42 | 43 | it("check textarea", function() { 44 | expect(field.className).toBe("form-group col-md-12"); 45 | expect(field.firstChild.localName).toBe("label"); 46 | expect(field.childElementCount).toBe(2); 47 | expect(field.outerHTML).toBe(field_outerHTML) 48 | expect(field.lastChild.textContent).toBe("description"); 49 | }); 50 | 51 | 52 | }) 53 | 54 | describe("Test field: radio", function() { 55 | var data = { 56 | "field": "radio", 57 | "width": "col-md-12", 58 | "items": [ 59 | { "text": "item1", "value": 1 }, 60 | { "text": "item2", "value": 2 }, 61 | { "text": "item3", "checked": true, "value": 3 } 62 | ], 63 | "name": "radio", 64 | "label": "radio", 65 | "helpBlock": "description" 66 | }, 67 | field = new MyFORM.field.factory(data); 68 | field = field.html(); 69 | 70 | it("radio", function() { 71 | expect(field.className).toBe("form-group col-md-12"); 72 | expect(field.firstChild.localName).toBe("label"); 73 | expect(field.childElementCount).toBe(4); 74 | expect(field.lastChild.textContent).toBe("description"); 75 | }); 76 | 77 | }) 78 | 79 | 80 | describe("Test field: select", function() { 81 | 82 | var data = { 83 | "field": "select", 84 | "width": "col-md-12", 85 | "items": [ 86 | { "text": "item1", "value": 1 }, 87 | { "text": "item2", "value": 2 }, 88 | { "text": "item3", "selected": true, "value": 3 } 89 | ], 90 | "name": "selected", 91 | "label": "selected", 92 | "helpBlock": "description" 93 | }, 94 | field = new MyFORM.field.factory(data); 95 | field = field.html(); 96 | 97 | it("select", function() { 98 | expect(field.className).toBe("form-group col-md-12"); 99 | expect(field.firstChild.localName).toBe("label"); 100 | expect(field.childElementCount).toBe(2); 101 | expect(field.children[1].localName).toBe("select"); 102 | expect(field.children[1][0].localName).toBe("option"); 103 | expect(field.lastChild.textContent).toBe("description"); 104 | console.log(field); 105 | }); 106 | 107 | }) 108 | describe("Test field: checkbox", function() { 109 | 110 | var data = { 111 | "field": "checkbox", 112 | "width": "col-md-12", 113 | "items": [ 114 | { "text": "item1", "value": 1 }, 115 | { "text": "item2", "checked": true, "value": 3 } 116 | ], 117 | "name": "checkbox", 118 | "label": "checkbox", 119 | "helpBlock": "description" 120 | }, 121 | field = new MyFORM.field.factory(data); 122 | field = field.html(); 123 | 124 | it("check htmlElement - checkbox", function() { 125 | expect(field.className).toBe("form-group col-md-12"); 126 | expect(field.firstChild.localName).toBe("label"); 127 | expect(field.childElementCount).toBe(3); 128 | expect(field.lastChild.textContent).toBe("description"); 129 | }); 130 | 131 | }) 132 | 133 | describe("Test field: description", function() { 134 | 135 | var data = { 136 | "field": "description", 137 | "width": "col-md-12", 138 | "textdescription": "

description

", 139 | "id": "id", 140 | "class": "class" 141 | }, 142 | field = new MyFORM.field.factory(data); 143 | field = field.html(); 144 | 145 | it("check htmlElement - description", function() { 146 | expect(field.className).toBe("class col-md-12"); 147 | expect(field.childElementCount).toBe(1); 148 | expect(field.outerHTML).toBe('

description

') 149 | }); 150 | 151 | }) 152 | 153 | describe("Test field: button with label", function() { 154 | 155 | var data = { 156 | "field": "submit", 157 | "width": "col-md-12", 158 | "label": "submit", 159 | "backgroundcolor": "btn-primary" 160 | }, 161 | field = new MyFORM.field.factory(data); 162 | field = field.html(); 163 | 164 | it("check htmlElement - description", function() { 165 | expect(field.className).toBe("form-group col-md-12"); 166 | expect(field.childElementCount).toBe(1); 167 | expect(field.outerHTML).toBe('
') 168 | }); 169 | 170 | }) 171 | 172 | describe("Test field: button without label", function() { 173 | 174 | var data = { 175 | "field": "submit", 176 | "width": "col-md-12", 177 | "backgroundcolor": "btn-primary", 178 | "id": "id", 179 | "class": "class" 180 | }, 181 | field = new MyFORM.field.factory(data); 182 | field = field.html(); 183 | 184 | it("check htmlElement - description", function() { 185 | expect(field.className).toBe("form-group col-md-12"); 186 | expect(field.childElementCount).toBe(1); 187 | expect(field.outerHTML).toBe('
') 188 | }); 189 | 190 | }) 191 | -------------------------------------------------------------------------------- /tests/js/formTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test for form.js 3 | * @author Rafal Marguzewicz 4 | * @license MIT 5 | * @return {undefined} 6 | * 7 | * .toBe() 8 | * .toBeCloseTo(expected, precisionopt) 9 | * .toEqual() // Equal object 10 | * .toBeDefined() - "The 'toBeDefined' matcher compares against `undefined`" 11 | * .toBeUndefined() 12 | * .toBeFalsy() 13 | * .toBeGreaterThan(expected) 14 | * .toBeGreaterThanOrEqual(expected) 15 | * .toBeLessThan(expected) 16 | * .toBeLessThanOrEqual(expected) 17 | * .toBeNan() 18 | * .toBeNull() 19 | * .toBeTruthy() 20 | * .toBeLessThanOrEqual(expected) 21 | * .toHaveBeenCalled() 22 | * .toHaveBeenCalledBefore() 23 | * .toHaveBeenCalledTimes(3) 24 | * .toHaveBeenCalledWith() 25 | * .toMatch() 26 | * .toThrow() 27 | */ 28 | console.log("FormTest: 1.0.0"); 29 | 30 | var field_input = { 31 | "field": "input", 32 | "type": "text", 33 | "width": "col-md-12", 34 | "name": "name", 35 | "label": "label", 36 | "value": "value", 37 | "require": true 38 | }, 39 | field_radio = { 40 | "field": "radio", 41 | "width": "col-md-12", 42 | "items": [ 43 | { "text": "item1", "value": 1 }, 44 | { "text": "item2", "value": 2 }, 45 | { "text": "item3", "checked": true, "value": 3 } 46 | ], 47 | "name": "radio", 48 | "label": "radio" 49 | }, 50 | body_form = { 51 | "url": "testurl", 52 | "title": "testtitle", 53 | "maximum": 30, 54 | "date_end": "2017-12-31", 55 | "action": "index.php", 56 | "id": "testid", 57 | "method": "get", 58 | "class": "testclass", 59 | "body":'[[{ "field": "input", "type": "text", "width": "col-md-12", "name": "name", "label": "label", "value": "value", "require": true }]]', 60 | } 61 | 62 | describe("Test1 form: init", function() { 63 | var form = new MyFORM.Form(); 64 | form.init({"autosave": true}); 65 | form.setView('text'); 66 | 67 | it("Generate form", function(){ 68 | form.generate(body_form); 69 | //expect(form.model.body).toEqual([[field_input]]); 70 | expect(form.model.title).toBe("testtitle"); 71 | expect(form.model.url).toBe("testurl"); 72 | expect(form.model.maximum).toBe(30); 73 | expect(form.model.date_end).toBe("2017-12-31"); 74 | expect(form.model.action).toBe("index.php"); 75 | expect(form.model.class).toBe("testclass"); 76 | expect(form.model.method).toBe("get"); 77 | expect(form.model.language).toBe("en"); 78 | }); 79 | 80 | it("form init", function() { 81 | expect(form.c.autosave).toBe(true); 82 | expect(form.c.get).toBe(false); 83 | }); 84 | 85 | it("Add bad field", function() { 86 | var add = form.add({}); 87 | expect(add).toBeFalsy(); 88 | }); 89 | 90 | }); 91 | 92 | describe("Test2 form: add, delete, add unique", function() { 93 | var form2 = new MyFORM.Form(); 94 | form2.init({"autosave": true}); 95 | form2.setView('text'); 96 | 97 | it("Add field", function() { 98 | form2.add(field_input); 99 | //expect(form2.model.body).toEqual([[field_input]]); 100 | }); 101 | 102 | 103 | it("delete field", function() { 104 | //expect(form2.deleteField(0,0)).toBe(true); 105 | }); 106 | 107 | it("Add field and unique name", function() { 108 | var field_copy = field_input; 109 | field_copy.name = field_input.name + '_2'; 110 | form2.add(field_input); 111 | //expect(form2.model.body).toEqual([[], [field_input]]); 112 | 113 | form2.add(field_input); 114 | //expect(form2.model.body).toEqual( [field_copy]); 115 | }); 116 | }); 117 | 118 | describe("Test3 form: change table names", function() { 119 | var form = new MyFORM.Form(); 120 | form.init({"autosave": true}); 121 | form.viewMode = 'text'; 122 | 123 | it("change name", function() { 124 | expect(form.editTableName({"old_name": "name", "new_name": "name"})).toBe(false); 125 | expect(form.editTableName({"old_name": "" ,"new_name": "name"})).toBe(false); 126 | expect(form.editTableName({"old_name": "" ,"new_name": ""})).toBe(false); 127 | expect(form.editTableName({"old_name": "good" ,"new_name": "well"})).toBe(true); 128 | form.c.autosave = false; 129 | expect(form.editTableName({"old_name": "good" ,"new_name": "well"})).toBe(false); // if autosace is false editTableName() return false 130 | 131 | }); 132 | 133 | it("form filter", function() { 134 | expect(form.filter(field_input)).toEqual(field_input); 135 | expect(form.filter()).toBe(false); 136 | }); 137 | }); 138 | 139 | describe("Test3 form: add clone delete add clone", function() { 140 | var form = new MyFORM.Form(), 141 | field = { "field": "input", "type": "text", "width": "col-md-12", "name": "name", "label": "label", }, 142 | field2 = { "field": "input", "type": "text", "width": "col-md-12", "name": "name_2", "label": "label_2", }, 143 | field3 = { "field": "input", "type": "text", "width": "col-md-12", "name": "name_2_2", "label": "label_2", }; 144 | 145 | form.init({"autosave": true}); 146 | form.viewMode = 'text'; 147 | form.add(field); // 1 field name 148 | 149 | it("clone field", function() { 150 | var field = form.model.body[0][0]; 151 | form.cloneField(0,0); // 2 fields name_2 152 | expect(form.model.body[0][1]).toEqual(field2); 153 | form.deleteField(0,1) // 1 fields 154 | form.add(field); // 2 fields name_2 155 | form.cloneField(1,0) // 3 fileds name_2_2 156 | expect(form.model.body[1][1]).toEqual(field3); 157 | }); 158 | 159 | }); 160 | -------------------------------------------------------------------------------- /tests/js/helpersTest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * .toBe() 5 | * .toBeCloseTo(expected, precisionopt) 6 | * .toEqual() 7 | * .toBeDefined() - "The 'toBeDefined' matcher compares against `undefined`" 8 | * .toBeUndefined() 9 | * .toBeFalsy() 10 | * .toBeGreaterThan(expected) 11 | * .toBeGreaterThanOrEqual(expected) 12 | * .toBeLessThan(expected) 13 | * .toBeLessThanOrEqual(expected) 14 | * .toBeNan() 15 | * .toBeNull() 16 | * .toBeTruthy() 17 | * .toBeLessThanOrEqual(expected) 18 | * .toHaveBeenCalled() 19 | * .toHaveBeenCalledBefore() 20 | * .toHaveBeenCalledTimes(3) 21 | * .toHaveBeenCalledWith() 22 | * .toMatch() 23 | * .toThrow() 24 | */ 25 | 26 | describe("Test helpers:",function(){ 27 | 28 | var o = { 29 | 'var1': "string", 30 | 'var2': null, 31 | 'var3': undefined, 32 | } 33 | 34 | var o2 = { 35 | 'var1': "string", 36 | } 37 | 38 | it("First capitalize",function(){ 39 | expect('String').toEqual(h.capitalizeFirstLetter('string')); 40 | }); 41 | 42 | it("Clear object from null and undefined",function(){ 43 | expect(h.clearObject(o)).toEqual(o2); 44 | }); 45 | 46 | it("Clone object",function(){ 47 | expect(h.clone(o)).toEqual(o); 48 | }); 49 | 50 | 51 | it("fibonacci",function(){ 52 | expect(h.fibonacci(0)).toEqual(0); 53 | expect(h.fibonacci(1)).toEqual(1); 54 | expect(h.fibonacci(2)).toEqual(1); 55 | expect(h.fibonacci(3)).toEqual(2); 56 | expect(h.fibonacci(4)).toEqual(3); 57 | expect(h.fibonacci(5)).toEqual(5); 58 | expect(h.fibonacci(6)).toEqual(8); 59 | expect(h.fibonacci(7)).toEqual(13); 60 | expect(h.fibonacci(8)).toEqual(21); 61 | expect(h.fibonacci(9)).toEqual(34); 62 | expect(h.fibonacci(10)).toEqual(55); 63 | expect(h.fibonacci(11)).toEqual(89); 64 | }); 65 | 66 | it("First propery of object",function(){ 67 | expect(h.firstProp(o)).toEqual('var1'); 68 | }); 69 | it("First propery of object",function(){ 70 | expect(h.firstProp(null)).toBeFalsy(); 71 | }); 72 | 73 | 74 | it("First value of object",function(){ 75 | expect("string").toEqual(h.firstValue(o)); 76 | }); 77 | it("First value of object",function(){ 78 | expect(h.firstValue(h.clone())).toBe(); 79 | }); 80 | 81 | 82 | it("is String",function(){ 83 | expect(h.isString('string')).toBe(true); 84 | expect(h.isString(false)).toBeFalsy(); 85 | expect(h.isString({})).toBeFalsy(); 86 | expect(h.isString()).toBeFalsy(); 87 | expect(h.isString([])).toBeFalsy(); 88 | }); 89 | 90 | it("is",function(){ 91 | expect(h.is('string')).toBe(true); 92 | expect(h.is(0)).toBe(true); 93 | expect(h.is(1)).toBe(true); 94 | expect(h.is(false)).toBe(true); 95 | expect(h.is({})).toBe(true); 96 | 97 | expect(h.is()).toBeFalsy(); 98 | expect(h.is('')).toBeFalsy(); 99 | expect(h.is(null)).toBeFalsy(); 100 | expect(h.is(undefined)).toBeFalsy(); 101 | }); 102 | 103 | it("is Boolean",function(){ 104 | expect(h.isBoolean('string')).toBe(false); 105 | expect(h.isBoolean(0)).toBe(false); 106 | expect(h.isBoolean(1)).toBe(false); 107 | expect(h.isBoolean(false)).toBe(true); 108 | }); 109 | 110 | it("is Array",function(){ 111 | expect(h.isArray([])).toBe(true); 112 | expect(h.isArray({})).toBeFalsy(); 113 | expect(h.isArray('')).toBeFalsy(); 114 | expect(h.isArray(o)).toBeFalsy(); 115 | expect(h.isArray('string')).toBeFalsy(); 116 | }); 117 | 118 | 119 | it("is Object",function(){ 120 | expect(h.isObject(o)).toBe(true); 121 | expect(h.isObject({})).toBe(true); 122 | expect(h.isObject([])).toBe(true); // tez object 123 | expect(h.isObject('string')).toBe(false); 124 | expect(h.isObject(0)).toBe(false); 125 | expect(h.isObject(1)).toBe(false); 126 | expect(h.isObject(false)).toBe(false); 127 | }); 128 | 129 | it('replace char', function () { 130 | expect(h.replaceChars('a b c', '-')).toBe('a-b-c') 131 | expect(h.replaceChars('a-b-c', '-')).toBe('a-b-c') 132 | expect(h.replaceChars('a-b-c', '-')).toBe('a-b-c') 133 | expect(h.replaceChars('a/b/c', '-')).toBe('a-b-c') 134 | expect(h.replaceChars('a\\b\\c')).toBe('a_b_c') 135 | expect(h.replaceChars('a\\b\\c', '-')).toBe('a-b-c') 136 | expect(h.replaceChars('a#b#c', '-')).toBe('a-b-c') 137 | expect(h.replaceChars('a.b.c', '-')).toBe('a-b-c') 138 | expect(h.replaceChars('', '-')).toBe('') 139 | expect(h.replaceChars('!@#$$%^&><:"{}')).toBe('_') 140 | }); 141 | 142 | 143 | it('subString', function () { 144 | expect(h.subString('Adam', 1)).toBe('A...') 145 | expect(h.subString('Adam', 2)).toBe('Ad...') 146 | expect(h.subString('12345678901')).toBe('1234567890...') 147 | expect(h.subString('abc')).toBe('abc') 148 | }); 149 | 150 | it('unique name', function () { 151 | expect(h.uniqueName('Adam', ['Adam', 'Adam_2'])).toBe('Adam_2_2') 152 | }); 153 | }); 154 | 155 | -------------------------------------------------------------------------------- /tests/js/lib/jasmine-2.6.2/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. 3 | 4 | If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. 5 | 6 | The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. 7 | 8 | [jasmine-gem]: http://github.com/pivotal/jasmine-gem 9 | */ 10 | 11 | (function() { 12 | 13 | /** 14 | * ## Require & Instantiate 15 | * 16 | * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. 17 | */ 18 | window.jasmine = jasmineRequire.core(jasmineRequire); 19 | 20 | /** 21 | * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. 22 | */ 23 | jasmineRequire.html(jasmine); 24 | 25 | /** 26 | * Create the Jasmine environment. This is used to run all specs in a project. 27 | */ 28 | var env = jasmine.getEnv(); 29 | 30 | /** 31 | * ## The Global Interface 32 | * 33 | * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. 34 | */ 35 | var jasmineInterface = jasmineRequire.interface(jasmine, env); 36 | 37 | /** 38 | * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. 39 | */ 40 | extend(window, jasmineInterface); 41 | 42 | /** 43 | * ## Runner Parameters 44 | * 45 | * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. 46 | */ 47 | 48 | var queryString = new jasmine.QueryString({ 49 | getWindowLocation: function() { return window.location; } 50 | }); 51 | 52 | var filterSpecs = !!queryString.getParam("spec"); 53 | 54 | var catchingExceptions = queryString.getParam("catch"); 55 | env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions); 56 | 57 | var throwingExpectationFailures = queryString.getParam("throwFailures"); 58 | env.throwOnExpectationFailure(throwingExpectationFailures); 59 | 60 | var random = queryString.getParam("random"); 61 | env.randomizeTests(random); 62 | 63 | var seed = queryString.getParam("seed"); 64 | if (seed) { 65 | env.seed(seed); 66 | } 67 | 68 | /** 69 | * ## Reporters 70 | * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). 71 | */ 72 | var htmlReporter = new jasmine.HtmlReporter({ 73 | env: env, 74 | onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); }, 75 | onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); }, 76 | onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); }, 77 | addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, 78 | getContainer: function() { return document.body; }, 79 | createElement: function() { return document.createElement.apply(document, arguments); }, 80 | createTextNode: function() { return document.createTextNode.apply(document, arguments); }, 81 | timer: new jasmine.Timer(), 82 | filterSpecs: filterSpecs 83 | }); 84 | 85 | /** 86 | * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. 87 | */ 88 | env.addReporter(jasmineInterface.jsApiReporter); 89 | env.addReporter(htmlReporter); 90 | 91 | /** 92 | * Filter which specs will be run by matching the start of the full name against the `spec` query param. 93 | */ 94 | var specFilter = new jasmine.HtmlSpecFilter({ 95 | filterString: function() { return queryString.getParam("spec"); } 96 | }); 97 | 98 | env.specFilter = function(spec) { 99 | return specFilter.matches(spec.getFullName()); 100 | }; 101 | 102 | /** 103 | * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. 104 | */ 105 | window.setTimeout = window.setTimeout; 106 | window.setInterval = window.setInterval; 107 | window.clearTimeout = window.clearTimeout; 108 | window.clearInterval = window.clearInterval; 109 | 110 | /** 111 | * ## Execution 112 | * 113 | * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. 114 | */ 115 | var currentWindowOnload = window.onload; 116 | 117 | window.onload = function() { 118 | if (currentWindowOnload) { 119 | currentWindowOnload(); 120 | } 121 | htmlReporter.initialize(); 122 | env.execute(); 123 | }; 124 | 125 | /** 126 | * Helper function for readability above. 127 | */ 128 | function extend(destination, source) { 129 | for (var property in source) destination[property] = source[property]; 130 | return destination; 131 | } 132 | 133 | }()); 134 | -------------------------------------------------------------------------------- /tests/js/lib/jasmine-2.6.2/console.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2017 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | function getJasmineRequireObj() { 24 | if (typeof module !== 'undefined' && module.exports) { 25 | return exports; 26 | } else { 27 | window.jasmineRequire = window.jasmineRequire || {}; 28 | return window.jasmineRequire; 29 | } 30 | } 31 | 32 | getJasmineRequireObj().console = function(jRequire, j$) { 33 | j$.ConsoleReporter = jRequire.ConsoleReporter(); 34 | }; 35 | 36 | getJasmineRequireObj().ConsoleReporter = function() { 37 | 38 | var noopTimer = { 39 | start: function(){}, 40 | elapsed: function(){ return 0; } 41 | }; 42 | 43 | function ConsoleReporter(options) { 44 | var print = options.print, 45 | showColors = options.showColors || false, 46 | onComplete = options.onComplete || function() {}, 47 | timer = options.timer || noopTimer, 48 | specCount, 49 | failureCount, 50 | failedSpecs = [], 51 | pendingCount, 52 | ansi = { 53 | green: '\x1B[32m', 54 | red: '\x1B[31m', 55 | yellow: '\x1B[33m', 56 | none: '\x1B[0m' 57 | }, 58 | failedSuites = []; 59 | 60 | print('ConsoleReporter is deprecated and will be removed in a future version.'); 61 | 62 | this.jasmineStarted = function() { 63 | specCount = 0; 64 | failureCount = 0; 65 | pendingCount = 0; 66 | print('Started'); 67 | printNewline(); 68 | timer.start(); 69 | }; 70 | 71 | this.jasmineDone = function() { 72 | printNewline(); 73 | for (var i = 0; i < failedSpecs.length; i++) { 74 | specFailureDetails(failedSpecs[i]); 75 | } 76 | 77 | if(specCount > 0) { 78 | printNewline(); 79 | 80 | var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' + 81 | failureCount + ' ' + plural('failure', failureCount); 82 | 83 | if (pendingCount) { 84 | specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount); 85 | } 86 | 87 | print(specCounts); 88 | } else { 89 | print('No specs found'); 90 | } 91 | 92 | printNewline(); 93 | var seconds = timer.elapsed() / 1000; 94 | print('Finished in ' + seconds + ' ' + plural('second', seconds)); 95 | printNewline(); 96 | 97 | for(i = 0; i < failedSuites.length; i++) { 98 | suiteFailureDetails(failedSuites[i]); 99 | } 100 | 101 | onComplete(failureCount === 0); 102 | }; 103 | 104 | this.specDone = function(result) { 105 | specCount++; 106 | 107 | if (result.status == 'pending') { 108 | pendingCount++; 109 | print(colored('yellow', '*')); 110 | return; 111 | } 112 | 113 | if (result.status == 'passed') { 114 | print(colored('green', '.')); 115 | return; 116 | } 117 | 118 | if (result.status == 'failed') { 119 | failureCount++; 120 | failedSpecs.push(result); 121 | print(colored('red', 'F')); 122 | } 123 | }; 124 | 125 | this.suiteDone = function(result) { 126 | if (result.failedExpectations && result.failedExpectations.length > 0) { 127 | failureCount++; 128 | failedSuites.push(result); 129 | } 130 | }; 131 | 132 | return this; 133 | 134 | function printNewline() { 135 | print('\n'); 136 | } 137 | 138 | function colored(color, str) { 139 | return showColors ? (ansi[color] + str + ansi.none) : str; 140 | } 141 | 142 | function plural(str, count) { 143 | return count == 1 ? str : str + 's'; 144 | } 145 | 146 | function repeat(thing, times) { 147 | var arr = []; 148 | for (var i = 0; i < times; i++) { 149 | arr.push(thing); 150 | } 151 | return arr; 152 | } 153 | 154 | function indent(str, spaces) { 155 | var lines = (str || '').split('\n'); 156 | var newArr = []; 157 | for (var i = 0; i < lines.length; i++) { 158 | newArr.push(repeat(' ', spaces).join('') + lines[i]); 159 | } 160 | return newArr.join('\n'); 161 | } 162 | 163 | function specFailureDetails(result) { 164 | printNewline(); 165 | print(result.fullName); 166 | 167 | for (var i = 0; i < result.failedExpectations.length; i++) { 168 | var failedExpectation = result.failedExpectations[i]; 169 | printNewline(); 170 | print(indent(failedExpectation.message, 2)); 171 | print(indent(failedExpectation.stack, 2)); 172 | } 173 | 174 | printNewline(); 175 | } 176 | 177 | function suiteFailureDetails(result) { 178 | for (var i = 0; i < result.failedExpectations.length; i++) { 179 | printNewline(); 180 | print(colored('red', 'An error was thrown in an afterAll')); 181 | printNewline(); 182 | print(colored('red', 'AfterAll ' + result.failedExpectations[i].message)); 183 | 184 | } 185 | printNewline(); 186 | } 187 | } 188 | 189 | return ConsoleReporter; 190 | }; 191 | -------------------------------------------------------------------------------- /tests/js/lib/jasmine-2.6.2/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pceuropa/yii2-forms/7cad71dc5d9d744d4dce0ef10b04ce49ed6f2a64/tests/js/lib/jasmine-2.6.2/jasmine_favicon.png -------------------------------------------------------------------------------- /tests/js/src/Player.js: -------------------------------------------------------------------------------- 1 | function Player() { 2 | } 3 | Player.prototype.play = function(song) { 4 | this.currentlyPlayingSong = song; 5 | this.isPlaying = true; 6 | }; 7 | 8 | Player.prototype.pause = function() { 9 | this.isPlaying = false; 10 | }; 11 | 12 | Player.prototype.resume = function() { 13 | if (this.isPlaying) { 14 | throw new Error("song is already playing"); 15 | } 16 | 17 | this.isPlaying = true; 18 | }; 19 | 20 | Player.prototype.makeFavorite = function() { 21 | this.currentlyPlayingSong.persistFavoriteStatus(true); 22 | }; -------------------------------------------------------------------------------- /tests/js/src/Song.js: -------------------------------------------------------------------------------- 1 | function Song() { 2 | } 3 | 4 | Song.prototype.persistFavoriteStatus = function(value) { 5 | // something complicated 6 | throw new Error("not yet implemented"); 7 | }; -------------------------------------------------------------------------------- /tests/php/_bootstrap.php: -------------------------------------------------------------------------------- 1 | wantTo('Not access for quest to forms/module/user'); 7 | $I->amOnRoute('forms/module/user'); 8 | $I->see('I forgot password.'); 9 | 10 | $I->wantTo('Not access for quest to forms/module/create'); 11 | $I->amOnRoute('forms/module/create'); 12 | $I->see('I forgot password.'); 13 | 14 | -------------------------------------------------------------------------------- /tests/php/functional/FormsCest.php: -------------------------------------------------------------------------------- 1 | amOnRoute($this->index); $I->seeElement($this->logo); 82 | 83 | $I->amOnPage([$this->list, 'id' => 15]); $I->seeElement($this->logo); 84 | 85 | $I->amOnRoute($this->create); $I->see($this->siteLogin); 86 | 87 | $I->amOnPage([$this->update, 'id' => 1]); $I->see($this->siteLogin); 88 | $I->amOnPage([$this->delete, 'id' => 1]); $I->see($this->siteLogin); 89 | 90 | $I->amOnPage([$this->view, 'url' => 'url']); $I->see($this->formPreview); 91 | } 92 | 93 | // otwieramy strony dostepne tylko dla user 1 94 | public function openFormsOnlyLoggedUser(\FunctionalTester $I) { 95 | $I->amLoggedInAs(1); 96 | 97 | $I->amOnRoute($this->index); $I->see('Forms'); 98 | 99 | $I->amOnRoute($this->list); $I->seeElement($this->logo); 100 | 101 | $I->amOnRoute($this->create); $I->see($this->formBuilderTitle); 102 | 103 | $I->amOnPage([$this->update, 'id' => 1]); $I->see($this->formBuilderTitle); 104 | $I->amOnPage([$this->delete, 'id' => 1]); $I->see($this->onlyPost); 105 | 106 | $I->amOnPage([$this->view, 'url' => 'url']); $I->see($this->formPreview); 107 | } 108 | 109 | // otwieramy strony jako user 2 dostepne tylkoa dla 1 110 | public function openFormsPageByAnotherUser(\FunctionalTester $I) { 111 | $I->amLoggedInAs(2); 112 | 113 | $I->amOnRoute($this->index); $I->see('Forms'); 114 | 115 | $I->amOnRoute($this->list); $I->seeElement($this->logo); 116 | 117 | $I->amOnRoute($this->create); $I->see($this->formBuilderTitle); 118 | 119 | $I->amOnPage([$this->update, 'id' => 1]); $I->see($this->notAllow); 120 | $I->amOnPage([$this->delete, 'id' => 20]); $I->see($this->onlyPost); 121 | 122 | $I->amOnPage([$this->view, 'url' => 'url']); $I->see($this->formPreview); 123 | } 124 | 125 | public function openFormsEndRegistration(\FunctionalTester $I) { 126 | 127 | $I->amOnPage([$this->view, 'url' => 'date']); 128 | $I->see($this->endRegistration); 129 | 130 | $I->amOnPage([$this->view, 'url' => 'maximum']); 131 | $I->see($this->endRegistration); 132 | 133 | $I->amOnPage([$this->view, 'url' => 'date-and-maximum']); 134 | $I->see($this->endRegistration); 135 | 136 | $I->amOnPage([$this->view, 'url' => 'date-null']); 137 | $I->see($this->endRegistration); 138 | 139 | $I->amOnPage([$this->view, 'url' => 'url']); 140 | $I->see($this->formPreview); 141 | } 142 | } 143 | 144 | -------------------------------------------------------------------------------- /tests/php/functional/_bootstrap.php: -------------------------------------------------------------------------------- 1 | "input", 20 | "name"=> "thinking", 21 | "type"=> "text", 22 | "label"=> "what are you thinking about", 23 | "width"=> "col-md-12", 24 | "require" => true 25 | ]; 26 | 27 | protected $radio_field = [ 28 | "field"=> "radio", 29 | "width"=> "col-md-6", 30 | "items"=> [ 31 | [ 32 | "text"=> "No", 33 | "value"=> "no", 34 | "checked"=> true 35 | ], 36 | [ 37 | "text"=> "Yes", 38 | "value"=> "yes" 39 | ] 40 | ], 41 | "name"=> "eat", 42 | "label"=> "You eat meat?" 43 | ]; 44 | 45 | protected function _before() { 46 | 47 | } 48 | 49 | protected function _after() { 50 | } 51 | 52 | /** 53 | * Check data from DB 54 | * @return array 55 | */ 56 | public function testCheckDataFromDB() { 57 | #$this->assertEquals('en', $this->form->language); 58 | } 59 | 60 | public function testOnlyCorrectDataFields() { 61 | } 62 | 63 | 64 | public function testTableSchema() { 65 | } 66 | 67 | 68 | public function testRuleType() { 69 | $rule1 = FormBase::ruleType($this->radio_field); 70 | $this->assertEquals('string', $rule1); 71 | 72 | $rule2 = FormBase::ruleType($this->input_field); 73 | $this->assertEquals('string', $rule2); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/php/unit/FormCreateTest.php: -------------------------------------------------------------------------------- 1 | I forgot my password.

","":"https://pceuropa.net/blog/"}],[{"field":"submit","width":"col-md-12","backgroundcolor":"btn-info","label":"Submit"}]]'; 47 | 48 | /** 49 | * @var array Form 50 | */ 51 | public $postData = [ 52 | 'title' => 'title', 53 | 'method' => 'post', 54 | 'language' => 'en', 55 | 'body' => '[[{"field":"description","width":"col-md-12","textdescription":"

Questionnaire

","":"1"},{"field":"input","name":"thinking","type":"text","label":"what are you thinking about","width":"col-md-12","require":true},{"field":"radio","width":"col-md-6","items":[{"text":"No","value":"no","checked":true},{"text":"Yes","value":"yes"}],"name":"trump","label":"Do you like Trump?"},{"field":"radio","width":"col-md-6","items":[{"text":"No","value":"no","checked":true},{"text":"Yes","value":"yes"}],"name":"eat","label":"You eat meat?"}],[{"field":"textarea","name":"ceta","width":"col-md-12","label":"What do you think about CETA?","require":true}],[],[{"field":"input","name":"age","type":"number","label":"Age","width":"col-md-4","require":true},{"field":"select","width":"col-md-4","items":[{"text":"Female","value":"female"},{"text":"Male","value":"male"},{"text":"I do not know","value":"0","checked":true}],"name":"sex","label":"Sex"},{"field":"input","name":"color","type":"color","label":"Favorite color","width":"col-md-4","require":true,"value":"#EAAE1B"}],[],[],[{"field":"checkbox","width":"col-md-12","items":[{"text":"C++","value":"c"},{"text":"Python","value":"python"},{"text":"JavaScript","value":"javascript"},{"text":"PHP","value":"php"},{"text":"Fortran","value":"fortran"}],"name":"framework","label":"What languages you know?"}],[],[{"field":"submit","width":"col-md-6","backgroundcolor":"btn-success","label":"Submit"}]]', 56 | 'url' => 'url', 57 | 'maximum' => 30, 58 | 'date_start' => '2015-11-11', 59 | 'date_end' => '2020-12-31' 60 | ]; 61 | /** 62 | * @var array Error not unique url 63 | */ 64 | public $notUniqueUrl = ['url' => 'URL "url" has already been taken.']; 65 | 66 | protected function _before() { 67 | $this->form = new FormBuilder([ 68 | 'formTable' => $this->formTable, 69 | 'formDataTable' => $this->formDataTable, 70 | 'formData' => $this->postData 71 | ]); 72 | } 73 | 74 | public function testInit() { 75 | $this->assertEquals( $this->form->db, 'db'); 76 | $this->assertEquals( $this->form->formDataTable, 'form_'); 77 | $this->assertFalse( $this->form->test_mode); 78 | $this->assertTrue( $this->form->easy_mode); 79 | $this->assertTrue(is_array($this->form->formData)); 80 | } 81 | 82 | public function testTableSchema() { 83 | $schema = $this->form->tableSchema($this->bodyForm); 84 | $this->assertEquals($schema, [ 85 | 'name' => 'string', 86 | 'pass' => 'string', 87 | 'remember' => 'string' 88 | ]); 89 | } 90 | 91 | public function testNotUniqueUrl() { 92 | $this->form->save(); 93 | $this->form->createTable(); 94 | $this->assertEquals($this->notUniqueUrl, $this->form->success); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /tests/php/unit/FormModelTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('mysql:host=localhost;dbname=yii2_basic_tests', $db->dsn); 15 | } 16 | 17 | public function testTable() { 18 | $tableName = FormModel::tableName(); 19 | $this->assertEquals('forms', $tableName); 20 | } 21 | public function testModelFindById() { 22 | $form = FormModel::findModel(1); 23 | $this->assertEquals('title', $form->title); 24 | } 25 | public function testModelFindByUrl() { 26 | $form = FormModel::findModelByUrl('url'); 27 | $this->assertEquals('title', $form->title); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/php/unit/FormUpdateTest.php: -------------------------------------------------------------------------------- 1 | I forgot my password.

","":"https://pceuropa.net/blog/"}],[{"field":"submit","width":"col-md-12","backgroundcolor":"btn-info","label":"Submit"}]]'; 20 | 21 | 22 | protected function _before() { 23 | $this->formBuilder = new FormBuilder([ 24 | 'formTable' => '{{%forms}}', 25 | 'formDataTable' => 'form_', 26 | ]); 27 | } 28 | 29 | public function testInit() { 30 | $this->assertEquals( $this->formBuilder->db, 'db'); 31 | $this->assertFalse( $this->formBuilder->test_mode); 32 | $this->assertTrue( $this->formBuilder->easy_mode); 33 | $this->assertFalse( $this->formBuilder->send_email); 34 | } 35 | 36 | public function testTableSchema() { 37 | $schema = $this->formBuilder->tableSchema($this->bodyForm); 38 | $this->assertEquals($schema, [ 39 | 'name' => 'string', 40 | 'pass' => 'string', 41 | 'remember' => 'string' 42 | ]); 43 | 44 | } 45 | 46 | public function testCreateTable() { 47 | $this->formBuilder->success = true; 48 | 49 | $form = new FormModel(); 50 | $form->body = '[]'; 51 | $form->url = 'test'; 52 | $form->title = 'title'; 53 | $form->save(); 54 | } 55 | public function testAddColumn() { 56 | } 57 | public function testRenameColumn() { 58 | } 59 | public function testDropColumn() { 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/php/unit/_bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
  1. 4 |
      5 |
    • View change the type of a code') ?>
    • 6 |
    • Title does not appear in a form code, is used for differentiation in a list of forms. If you need a title, use Field -> Description') ?>
    • 7 |
    • URL address the URL address of a form') ?>
    • 8 |
    • Method (HTTP) a way of data transmission between a form and a collection address') ?>
    • 9 |
    • Action leave blank if the URL collection address is the same as the address of a form') ?>
    • 10 |
    • ID allows setting an id attribute for a form, practicable for CSS') ?>
    • 11 |
    • Class allows setting a class attribute for a form, practicable for CSS') ?>
    • 12 |
    • Save the form an option for saving a form which is active upon filling the title and URL address fields') ?>
    • 13 |
    14 | 15 |
  2. 16 |
  3. Field options') ?> 17 |
      18 |
    • Selection menu allows to choose a particular element') ?>
    • 19 |
    • Name an attribute not visible in the form, required for differentiation of received data from filled forms') ?>
    • 20 |
    • Label a writing appearing above a field') ?>
    • 21 |
    • Placeholder tekst a description of a form field, localized in the field that disappears after you have started to fill in a given field') ?>
    • 22 |
    • Default text a field filled in automatically') ?>
    • 23 |
    • Description a descriptive text localized above a field') ?>
    • 24 |
    • Width a field may be of e.g. 50% width and then 2 fields may appear on a computer screen in a line. The field on a smart phone screen is always of 100% width') ?>
    • 25 |
    • Required a form field must be filled in') ?>
    • 26 |
    • ID allows setting an id attribute for a form, practicable for CSS') ?>
    • 27 |
    • Class allows setting a class attribute for a form, practicable for CSS') ?>
    • 28 |
    • Field elements in case of multiple choice fields') ?>
    • 29 |
        30 |
      1. Text text of one element from a field list') ?>
      2. 31 |
      3. Value will allow the differentiation of answers, leave blank if you are not sure, the system will paginate automatically') ?>
      4. 32 |
      5. Checked an element of a field list selected automatically') ?>
      6. 33 |
      34 | 35 |
    36 |
  4. 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /views/builder/_sidebar.php: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 |
26 |
27 | render('options/form', ['hide_button_form_save' => $hide_button_form_save]); ?> 28 |
29 | 30 |
render('options/input'); ?>
31 |
render('options/textarea'); ?>
32 |
render('options/multi-field'); ?>
33 |
render('options/multi-field'); ?>
34 |
render('options/select'); ?>
35 |
render('options/description'); ?>
36 |
render('options/submit'); ?>
37 |
38 | 39 |
40 | 41 |
42 | render('options/button/_back'); ?> 43 | render('options/button/_delete'); ?> 44 |
45 | 46 |
47 | -------------------------------------------------------------------------------- /views/builder/main.php: -------------------------------------------------------------------------------- 1 | 5 |
6 |
7 |

:

8 |
9 | 10 |
11 | 12 |
13 | 14 | : 15 |
16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 | 28 |
29 | 30 | registerCss(".expert {display:none}"); // hide many options 34 | } 35 | 36 | if ($generator_mode){ 37 | $this->registerCss(".generator_mode {display:none}"); // hide many options 38 | } 39 | $this->registerJs("var form = new MyFORM.Form(); ", 4); // init form.js 40 | 41 | if ($send_email){ 42 | // add module Email send after submit form (work if in forms is field with attribute name 'email') 43 | // form.modules are initalized each time the form is rendered 44 | $this->registerJs("form.modules.response = MyFORM.response()", 4); 45 | } 46 | $this->registerJs(" 47 | form.init(".Json::encode($jsConfig)."); 48 | form.controller(); 49 | ", 4); 50 | 51 | if ($test_mode){ 52 | $this->registerJs(" MyFORM.test(form);", 4); // init test form on begining 53 | } 54 | 55 | if (!$easy_mode){ 56 | $this->registerJs(" MyFORM.examples(form);", 4); // add module with examples of formsj 57 | } 58 | ?> 59 | -------------------------------------------------------------------------------- /views/builder/options/button/_add-item.php: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /views/builder/options/button/_add-to-form.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/button/_back.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /views/builder/options/button/_clone-item.php: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /views/builder/options/button/_delete-item.php: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /views/builder/options/button/_delete.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /views/builder/options/button/_save-form.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /views/builder/options/button/_showme.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /views/builder/options/description.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /views/builder/options/field/_backgroundcolor.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /views/builder/options/field/_class.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_color.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | -------------------------------------------------------------------------------- /views/builder/options/field/_description.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_help-block.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_id.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_label.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_name.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
*
4 | 5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /views/builder/options/field/_placeholder.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_rows.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_text.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_type.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 15 |
16 |
17 | -------------------------------------------------------------------------------- /views/builder/options/field/_value.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/field/_width-and-require.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 12 |
13 | 14 |
15 | 16 |
17 |
18 | -------------------------------------------------------------------------------- /views/builder/options/field/_width.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /views/builder/options/form.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 10 |
11 |
12 | 13 | 14 |
15 |
16 |
*
17 | 18 |
19 |
20 | 21 | 22 |
23 |
24 |
*
25 | 26 |
27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 |
39 | 43 |
44 |
45 | 46 |
47 |
48 |
49 | 50 |
51 |
52 | 53 |
54 |
55 |
56 | 57 |
58 |
59 | 60 |
61 |
62 |
63 | 67 |
68 |
69 | 70 |
71 |
72 |
73 | 74 |
75 |
76 | 77 | 78 | 79 |
80 |
81 |
82 | 83 |
84 |
85 | 86 |
87 | 90 |
91 | -------------------------------------------------------------------------------- /views/builder/options/input.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 14 |
15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /views/builder/options/item/_checked.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/item/_selected.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/item/_text.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/item/_value.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /views/builder/options/multi-field.php: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 |
13 | 14 | 15 | 20 | 21 |
22 |
23 | 24 |
25 |
26 |
27 | 28 | 29 |
30 | 35 |
36 | 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /views/builder/options/select.php: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 |
13 | 14 | 19 | 20 |
21 |
22 | 23 |
24 |
25 |
26 | 27 |
28 | 33 |
34 | 35 |
36 | 37 | -------------------------------------------------------------------------------- /views/builder/options/submit.php: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /views/builder/options/textarea.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /views/form_js.php: -------------------------------------------------------------------------------- 1 | 6 |
js forms not work
7 | registerJs("var form = new MyFORM.Form(); ", 4); 9 | $this->registerJs("form.init(".Json::encode($form).");", 4); 10 | ?> 11 | -------------------------------------------------------------------------------- /views/form_php.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'class' => 'pceuropa-form', 8 | ] 9 | ]); 10 | $date = (new \DateTime())->format('Y-m-d H:i:s'); 11 | echo(''); 12 | echo(""); 13 | 14 | if (count($form_body) != 0) { 15 | foreach($form_body as $key => $row) { 16 | echo('
'); 17 | foreach ($row as $key => $value) { 18 | echo $form->dynamicField($model, $value); 19 | } 20 | echo('
'); 21 | } 22 | } 23 | 24 | ActiveForm::end(); 25 | 26 | $this->registerCss(" 27 | .ql-align-center { text-align:center } 28 | .ql-align-right { text-align:right } 29 | "); 30 | ?> 31 | -------------------------------------------------------------------------------- /views/index.php: -------------------------------------------------------------------------------- 1 |
js forms not work
2 | 3 | registerJsFile('/js/forms/creator.js', ['position' => 3, 'depends' => 'yii\web\YiiAsset']); 5 | $this->registerJsFile('/js/forms/fields.js', ['position' => 3, 'depends' => 'yii\web\YiiAsset']); 6 | $this->registerJs(" 7 | var form = new MyFORM.Form(); 8 | form.generate(".$form_body."); 9 | ", 3); 10 | ?> 11 | -------------------------------------------------------------------------------- /views/module/create.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('builder', 'Form generator Yii2'); 6 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'All forms') , 'url' => ['index']]; 7 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'Your forms') , 'url' => ['user']]; 8 | $this->params['breadcrumbs'][] = Yii::t('builder', 'Create'); 9 | ?> 10 | $testMode, 12 | 'easy_mode' => $easyMode, 13 | 'send_email' => $sendEmail, 14 | ]); ?> 15 | -------------------------------------------------------------------------------- /views/module/end.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('builder', 'End registration'); 3 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'All forms') , 'url' => ['index']]; 4 | ?> 5 | 6 | 9 | -------------------------------------------------------------------------------- /views/module/gridview.php: -------------------------------------------------------------------------------- 1 | User->can('admin')) { 6 | $template = '{update} {view} {delete} | {clone}'; 7 | } 8 | 9 | ?> 10 | 11 |

12 | 13 | ', ['create'], ['class' => 'btn btn-success btn-sm']) ?> 14 |

15 | 16 | $dataProvider, 18 | 'filterModel' => $searchModel, 19 | 'columns' => [ 20 | ['class' => 'yii\grid\SerialColumn'], 21 | 'title', 22 | [ 23 | 'attribute' => 'url', 24 | 'format' => 'html', 25 | 'value' => function ($model) { 26 | return Html::a ($model->url, ['view', 'url' => $model->url], ['target' => 'new']); 27 | }, 28 | ],[ 29 | 'attribute' => 'answer', 30 | 'format' => 'html', 31 | 'value' => function ($model) { 32 | $maximum = null; 33 | if ($model->maximum !== null) { 34 | $maximum = ' /'. $model->maximum; 35 | } 36 | return html::a (' ' . $model->answer.$maximum, ['list', 'id' => $model->form_id]); 37 | }, 38 | ],[ 39 | 'attribute' => 'date_end', 40 | 'format' => 'datetime', 41 | ], 42 | 43 | ['class' => 'yii\grid\ActionColumn', 44 | 'buttons' => [ 45 | 'view' => function ($url, $model, $key) { 46 | return Html::a ( ' ', ['view', 'url' => $model->url] ); 47 | }, 48 | 'clone' => function ($url, $model, $key) { 49 | return Html::a ( Yii::t('builder', 'clone'), ['clone', 'id' => $model->form_id] ); 50 | }, 51 | ], 52 | 'template' => $template 53 | ], 54 | ], 55 | ]);?> 56 | 57 |
58 |
59 | -
60 | -
61 | -
62 | - 63 |
64 | 65 | -------------------------------------------------------------------------------- /views/module/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('builder', 'FormBuilder: Online form generator'); 3 | $this->params['breadcrumbs'][] = Yii::t('builder', 'Forms'); 4 | 5 | echo $this->render('gridview', [ 6 | 'buttonsEditOnIndex' => $buttonsEditOnIndex, 7 | 'searchModel' => $searchModel, 8 | 'dataProvider' => $dataProvider, 9 | ]); 10 | -------------------------------------------------------------------------------- /views/module/list.php: -------------------------------------------------------------------------------- 1 | title = $form->title; 5 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'Forms'), 'url' => ['index']]; 6 | $this->params['breadcrumbs'][] = $this->title; 7 | ?> 8 |

title) ?>

9 | 10 | $dataProvider, 12 | 'columns' => iterator_to_array($only_data_fields) 13 | ]); 14 | ?> 15 | -------------------------------------------------------------------------------- /views/module/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('builder', 'Form update') ; 7 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'All forms') , 'url' => ['index']]; 8 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'Your forms') , 'url' => ['user']]; 9 | $this->params['breadcrumbs'][] = $this->title; 10 | ?> 11 | 12 | Module::getInstance()->formTable, 14 | 'db' => Module::getInstance()->db, 15 | 'send_email' => $sendEmail, 16 | 'easy_mode' => $easyMode ?? true, 17 | 'jsConfig' => [ 18 | 'get'=> true, 19 | 'save'=> true, 20 | 'autosave' => true, 21 | ] 22 | ]); 23 | ?> 24 | -------------------------------------------------------------------------------- /views/module/user.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('builder', 'Forms'); 3 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'All forms') , 'url' => ['index']]; 4 | $this->params['breadcrumbs'][] = Yii::t('builder', 'Your forms') ; 5 | 6 | echo $this->render('gridview', [ 7 | 'searchModel' => $searchModel, 8 | 'dataProvider' => $dataProvider, 9 | ]); 10 | -------------------------------------------------------------------------------- /views/module/view.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('app', 'Form'). ': '. $form->title; 8 | $this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Forms') , 'url' => ['user']]; 9 | $this->params['breadcrumbs'][] = $this->title; 10 | ?> 11 | 12 | $form->body, 14 | 'typeRender' => 'php' 15 | ]); 16 | 17 | $this->registerJs(" 18 | var selector = $('input[name=\"_fp\"]'); 19 | if (selector.length) { 20 | Fingerprint2.get(function(c) { 21 | selector.val(Fingerprint2.x64hash128(c.map(function (pair) { return pair.value }).join(), 31)); 22 | }) 23 | }", 4); 24 | ?> 25 | -------------------------------------------------------------------------------- /views/module/view_only_once.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('builder', 'Twice response'); 5 | $this->params['breadcrumbs'][] = ['label' => Yii::t('builder', 'All forms') , 'url' => ['index']]; 6 | ?> 7 | 8 | 11 | $form_id]);?> 12 | --------------------------------------------------------------------------------