diff --git a/common/config/bootstrap.php b/common/config/bootstrap.php index d4a7ece..04b959f 100755 --- a/common/config/bootstrap.php +++ b/common/config/bootstrap.php @@ -1,7 +1,8 @@ 'Europe/Kiev', 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', @@ -28,6 +30,9 @@ 'artbox-comment' => [ 'class' => \common\modules\comment\Controller::className(), ], + 'fileloader' => [ + 'class' => FileloaderController::className(), + ], ], 'modules' => [ diff --git a/common/models/Project.php b/common/models/Project.php index 30c7322..651e073 100644 --- a/common/models/Project.php +++ b/common/models/Project.php @@ -3,9 +3,12 @@ namespace common\models; use common\modules\comment\models\CommentProject; + use common\modules\fileloader\behaviors\FileloaderBehavior; + use common\modules\fileloader\models\Fileloader; use Yii; use yii\behaviors\BlameableBehavior; use yii\behaviors\TimestampBehavior; + use yii\db\ActiveQuery; use yii\db\Expression; /** @@ -33,6 +36,8 @@ * @property Currency $budgetCurrency * @property Project $parent * @property int $hidden + * @property int[] $fileloader + * @method File[] getFileloaderFiles() */ class Project extends \yii\db\ActiveRecord { @@ -64,12 +69,15 @@ 'updatedAtAttribute' => false, 'value' => new Expression('NOW()'), ], - 'slug' => [ + 'slug' => [ 'class' => 'common\behaviors\Slug', 'in_attribute' => 'name', 'out_attribute' => 'link', 'translit' => true, ], + 'fileloader' => [ + 'class' => FileloaderBehavior::className(), + ], ]; } @@ -154,21 +162,21 @@ 'boolean', ], [ - ['hidden'], + [ 'hidden' ], 'default', 'value' => 0, ], [ - ['date_end'], + [ 'date_end' ], 'filter', 'filter' => function($value) { $unix = strtotime($value); if($unix <= time()) { - $unix = time() + (3600 * 24 * 7); + $unix = time() + ( 3600 * 24 * 7 ); } return date('Y-m-d', $unix); - } - ] + }, + ], ]; } @@ -332,4 +340,5 @@ return $this->hasMany(CommentProject::className(), [ 'model_id' => 'project_id' ]) ->andWhere([ 'model' => $this->className() ]); } + } diff --git a/common/modules/fileloader/Module.php b/common/modules/fileloader/Module.php new file mode 100644 index 0000000..a93f91d --- /dev/null +++ b/common/modules/fileloader/Module.php @@ -0,0 +1,23 @@ + View::POS_HEAD, + ]; + + } \ No newline at end of file diff --git a/common/modules/fileloader/behaviors/FileloaderBehavior.php b/common/modules/fileloader/behaviors/FileloaderBehavior.php new file mode 100644 index 0000000..8466e9b --- /dev/null +++ b/common/modules/fileloader/behaviors/FileloaderBehavior.php @@ -0,0 +1,116 @@ + 'afterSave', + ActiveRecord::EVENT_AFTER_UPDATE => 'afterSave', + ActiveRecord::EVENT_INIT => 'attachValidator', + ]; + } + + public function attachValidator($event) + { + $validator = Validator::createValidator('safe', $this->owner, 'fileloader'); + $this->owner->validators->append($validator); + } + + /** + * After saving model delete all relative files and insert new file connections from + * fileloader variable + * + * @param Event $event + */ + public function afterSave($event) + { + /** + * @var ActiveRecord $owner + * @var string $relation + */ + $owner = $this->owner; + $relation = $this->relationclass; + call_user_func([ + $relation, + 'deleteAll', + ], [ + 'model' => $owner->className(), + 'model_id' => $owner->primaryKey, + ]); + if(!empty( $owner->fileloader )) { + foreach($owner->fileloader as $file) { + /** + * @var ActiveRecord $model + */ + $model = new $relation([ + 'file_id' => $file, + 'model' => $owner->className(), + 'model_id' => $owner->primaryKey, + 'user_id' => \Yii::$app->user->getId(), + 'status' => 1, + ]); + if($model->validate()) { + $model->save(false); + } + unset( $model ); + } + } + } + + /** + * Bind owner class tp specified $fileclass via $relationclass table. + * @return ActiveQuery + */ + public function getFileloaderFiles() + { + /** + * @var ActiveRecord $owner + */ + $owner = $this->owner; + $relationtable = call_user_func([ + $this->relationclass, + 'tableName', + ]); + return $owner->hasMany($this->fileclass, [ 'file_id' => 'file_id' ]) + ->viaTable($relationtable, [ 'model_id' => $owner->primaryKey()[ 0 ] ], function($query) use ($owner) { + /** + * @var ActiveQuery $query + */ + $query->andWhere([ + 'model' => $owner->className(), + 'status' => 1, + ]); + }); + } + } \ No newline at end of file diff --git a/common/modules/fileloader/controllers/FileloaderController.php b/common/modules/fileloader/controllers/FileloaderController.php new file mode 100644 index 0000000..ff7875d --- /dev/null +++ b/common/modules/fileloader/controllers/FileloaderController.php @@ -0,0 +1,105 @@ + [ + 'class' => AccessControl::className(), + 'rules' => [ + [ + 'allow' => true, + 'roles' => [ '@' ], + ], + ], + ], + 'verbs' => [ + 'class' => \yii\filters\VerbFilter::className(), + 'actions' => [ + '*' => [ 'post' ], + ], + ], + ]; + } + + /** + * Handle ajax file uploading + * + * @return array + */ + public function actionUpload() + { + $request = \Yii::$app->request; + $response = \Yii::$app->response; + $response->format = $response::FORMAT_JSON; + $model = new Fileloader(); + $model->files = UploadedFile::getInstance($model, 'files'); + if(!empty( $model->files )) { + $file_id = $model->saveFile($model->files); + if(!empty( $file_id )) { + $child_model = $request->post('model', $model->className()); + $child_model = new $child_model([ 'file' => $file_id ]); + $input = Html::activeHiddenInput($child_model, 'fileloader[]', [ + 'value' => $file_id, + 'class' => 'fileloader-item-input', + ]); + return [ + 'result' => [ + 'file_id' => $file_id, + 'file_name' => $model->name, + 'file_href' => $model->dir, + 'input' => $input, + 'id' => $request->post('id'), + ], + ]; + } else { + return [ 'error' => 'Ошибка сохранения файла' ]; + } + } + return [ 'error' => 'Ошибка загрузки' ]; + } + + /** + * Handle ajax file deleting + * + * @return array + */ + public function actionDelete() + { + /** + * @var Fileloader $model + */ + $request = \Yii::$app->request; + $response = \Yii::$app->response; + $response->format = $response::FORMAT_JSON; + if(empty( $request->post('id') )) { + return [ 'error' => 'Не указан id файла' ]; + } + $model = Fileloader::find() + ->where([ + 'file_id' => $request->post('id'), + 'user_id' => \Yii::$app->user->getId(), + ]) + ->one(); + if(empty( $model )) { + return [ 'error' => 'Файл не найден' ]; + } + if($model->delete()) { + return [ 'result' => [ 'message' => 'Файл успешно удален' ] ]; + } else { + return [ 'error' => 'Ошибка удаления файла' ]; + } + } + + } \ No newline at end of file diff --git a/common/modules/fileloader/models/FileRelation.php b/common/modules/fileloader/models/FileRelation.php new file mode 100644 index 0000000..15db765 --- /dev/null +++ b/common/modules/fileloader/models/FileRelation.php @@ -0,0 +1,79 @@ + 255], + [['file_id'], 'exist', 'skipOnError' => true, 'targetClass' => File::className(), 'targetAttribute' => ['file_id' => 'file_id']], + [['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']], + ]; + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'file_relation_id' => Yii::t('app', 'File Relation ID'), + 'file_id' => Yii::t('app', 'File ID'), + 'model' => Yii::t('app', 'Model'), + 'model_id' => Yii::t('app', 'Model ID'), + 'user_id' => Yii::t('app', 'User ID'), + 'date_add' => Yii::t('app', 'Date Add'), + 'status' => Yii::t('app', 'Status'), + ]; + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getFile() + { + return $this->hasOne(File::className(), ['file_id' => 'file_id']); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getUser() + { + return $this->hasOne(User::className(), ['id' => 'user_id']); + } +} diff --git a/common/modules/fileloader/models/Fileloader.php b/common/modules/fileloader/models/Fileloader.php new file mode 100644 index 0000000..03eba2a --- /dev/null +++ b/common/modules/fileloader/models/Fileloader.php @@ -0,0 +1,103 @@ + BlameableBehavior::className(), + 'createdByAttribute' => 'user_id', + 'updatedByAttribute' => false, + ], + ]; + } + + /** + * @inheritdoc + */ + public function rules() + { + return [ + [['status'], 'integer'], + [['name'], 'string', 'max' => 50], + [['dir'], 'string', 'max' => 255], + ]; + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'file_id' => 'File ID', + 'status' => 'Status', + 'name' => 'Name', + 'dir' => 'Dir', + ]; + } + + /** + * @param UploadedFile $file + * @return int file id in model File + */ + public function saveFile(UploadedFile $file){ + $imgDir = Yii::getAlias('@storage/'.'user_'.\Yii::$app->user->id.'/files/'); + $uploadName = preg_replace('/\s/', '_', $file->baseName).'_'. time().'.'.$file->extension; + $uploadName = Tools::translit($uploadName, 'letter'); + if(!is_dir($imgDir)) { + mkdir($imgDir, 0755, true); + } + if($file->saveAs($imgDir.$uploadName)){ + $this->dir = '/storage/user_'.\Yii::$app->user->id.'/files/'.$uploadName; + $this->name = preg_replace('/\s/', '_', $file->baseName).'.'.$file->extension; + $this->save(); + return $this->file_id; + } + } + + /** + * Extends ActiveRecord::delete() method, also deletes file from file system + * + * @see ActiveRecord::delete() + * @return false|int + * @throws \Exception + */ + public function delete() + { + if(!empty($this->dir)) { + if(file_exists(Yii::getAlias('@documentRoot').$this->dir)) { + unlink(Yii::getAlias('@documentRoot').$this->dir); + } + } + return parent::delete(); + } +} diff --git a/common/modules/fileloader/resources/fileloader.css b/common/modules/fileloader/resources/fileloader.css new file mode 100644 index 0000000..effe6f0 --- /dev/null +++ b/common/modules/fileloader/resources/fileloader.css @@ -0,0 +1,17 @@ +.fileloader-item-name { + display: inline-block; +} +.fileloader-item-name a { + text-decoration: none; + border-bottom: dotted 1px; +} +.fileloader-item-name a:hover, .fileloader-item-name a:focus { + text-decoration: none; +} +.fileloader-item-remove { + padding-left: 10px; + cursor: pointer; +} +.fileloader-file { + position: relative; +} \ No newline at end of file diff --git a/common/modules/fileloader/resources/handler.js b/common/modules/fileloader/resources/handler.js new file mode 100644 index 0000000..d63bb5d --- /dev/null +++ b/common/modules/fileloader/resources/handler.js @@ -0,0 +1,45 @@ +$(function() { + if(fileloader !== undefined) { + $.each(fileloader, function(index, value) { + var id = value.id; + var model = value.model; + var formData = {}; + if(typeof model == 'string' && model !== '') { + formData.model = model; + } + if(typeof id == 'string' && id !== '') { + formData.id = id; + $('#'+id).fileupload({ + dataType: 'json', + url: '/fileloader/upload', + formData: formData, + done: function(e, data) { + if(!data.result.error) { + var id = data.result.result.id; + var input = $('#'+id); + var wrapper = $(input).parents('.fileloader-wrapper').first(); + var html = '
'+ + data.result.result.input + '

'+ + ''+data.result.result.file_name+'

'+''+ + '
'; + $(html).appendTo($(wrapper).find('.fileloader-list')); + } + } + }); + } + }); + } + + $(document).on('click', '.fileloader-item-remove', function(e) { + var wrapper = $(this).parents('.fileloader-item-wrapper').first(); + var id = $(wrapper).data('id'); + $.post( + '/fileloader/delete', + { + id: id + }, + function(data) {} + ); + $(wrapper).remove(); + }); +}); diff --git a/common/modules/fileloader/widgets/FileloaderWidget.php b/common/modules/fileloader/widgets/FileloaderWidget.php new file mode 100644 index 0000000..3cceb81 --- /dev/null +++ b/common/modules/fileloader/widgets/FileloaderWidget.php @@ -0,0 +1,300 @@ +Special: 1. You cannot modify 'for' attribute + */ + public $labelOptions = [ ]; + + /** + * @var array $inputOptions Input options. + * + * Special: + * 1. You cannot modify 'id' attribute. + * 2. Class will be appended by base input class + * + */ + public $inputOptions = [ ]; + + /** + * @var array $hintOptions Hint options. + * + * 1. tag will be used to generate container tag. Default to 'div' + * 2. value will be used to generate content. If missing, component won't be rendered + * + */ + public $hintOptions = [ ]; + + /** + * @var array $errorOptions Error options + * + * 1. tag will be used to generate container tag. Default to 'div' + * 2. class will be appended by base error class + * + */ + public $errorOptions = [ ]; + + /** + * @var array $listOptions Items list options + * + * 1. tag will be used to generate container tag. Default to 'div' + * 2. class will be appended by base list class + * + */ + public $listOptions = [ ]; + + /** + * @var array $options Container options + * + * 1. tag will be used to generate container tag. Default to 'div' + * 2. class will be appended by base wrapper class + * + */ + public $options = [ ]; + + /** + * @var ActiveRecord $model Model where to insert files + */ + public $model; + + /** + * @var string $attribute Model attribute + */ + public $attribute; + + /** + * @var View $view Current view object + */ + public $view; + + /** + * @var string $template Widget template. Recognised components: {label}, {input}, {hint}, + * {error}, {list} + */ + public $template = '{label}{input}{hint}{error}{list}'; + + /** + * @var bool $displayLabel Whether to display label component or not + */ + public $displayLabel = true; + + /** + * @var bool $displayInput Whether to display input component or not + */ + public $displayInput = true; + + /** + * @var bool $displayHint Whether to display hint component or not + */ + public $displayHint = true; + + /** + * @var bool $displayError Whether to display error component or not + */ + public $displayError = true; + + /** + * @var bool $displayList Whether to display list component or not + */ + public $displayList = true; + + protected $label = ''; + + protected $input = ''; + + protected $hint = ''; + + protected $error = ''; + + protected $list = ''; + + /** + * @var string Unique widget ID + */ + protected $inputID; + + /** + * @var Fileloader $fileloader Fileloader model + */ + protected $fileloader; + + protected $output = ''; + + /** + * @var string $baseClass Will be added to input component + */ + protected $baseClass = ' fileloader-input'; + + /** + * @var string $baseErrorClass Will be added to error container + */ + protected $baseErrorClass = ' fileloader-error'; + + /** + * @var string $baseListClass Will be added to list container + */ + protected $baseListClass = ' fileloader-list'; + + /** + * @var string $baseWrapperClass Will be added to Container + */ + protected $baseWrapperClass = ' fileloader-wrapper'; + + /** + * @inheritdoc + */ + public function init() + { + parent::init(); + FileloaderAsset::register($this->view); + } + + /** + * @inheritdoc + * @return string + */ + public function run() + { + $this->fileloader = new Fileloader(); + $this->inputID = 'fileloader-' . $this->getId(); + $this->createParts(); + $this->output = $this->renderLoader(); + $this->renderJS(); + return $this->output; + } + + /** + * Fills widget components with data + */ + public function createParts() + { + if(!empty( $this->displayLabel ) && preg_match('/^.*\{label\}.*$/i', $this->template)) { + $this->labelOptions[ 'for' ] = $this->inputID; + $this->label = Html::activeLabel($this->fileloader, 'files', $this->labelOptions); + } + if(!empty( $this->displayInput ) && preg_match('/^.*\{input\}.*$/i', $this->template)) { + if(empty( $this->inputOptions[ 'class' ] )) { + $this->inputOptions[ 'class' ] = $this->baseClass; + } else { + $this->inputOptions[ 'class' ] .= $this->baseClass; + } + $this->inputOptions[ 'id' ] = $this->inputID; + $this->input = Html::activeFileInput($this->fileloader, 'files', $this->inputOptions); + } + if(!empty( $this->displayHint ) && preg_match('/^.*\{hint\}.*$/i', $this->template) && !empty( $this->hintOptions[ 'value' ] )) { + $this->hint = Html::tag(ArrayHelper::remove($this->hintOptions, 'tag', 'div'), ArrayHelper::remove($this->hintOptions, 'value'), $this->hintOptions); + } + if(!empty( $this->displayError ) && preg_match('/^.*\{error\}.*$/i', $this->template)) { + if(empty( $this->errorOptions[ 'class' ] )) { + $this->errorOptions[ 'class' ] = $this->baseErrorClass; + } else { + $this->errorOptions[ 'class' ] .= $this->baseErrorClass; + } + $this->error = Html::tag(ArrayHelper::remove($this->errorOptions, 'tag', 'div'), '', $this->errorOptions); + } + if(!empty( $this->displayList ) && preg_match('/^.*\{list\}.*$/i', $this->template)) { + if(empty( $this->listOptions[ 'class' ] )) { + $this->listOptions[ 'class' ] = $this->baseListClass; + } else { + $this->listOptions[ 'class' ] .= $this->baseListClass; + } + $list = ''; + $items = $this->getItems(); + if(!empty( $items )) { + foreach($items as $item) { + $list .= '
' . Html::activeHiddenInput($this->model, 'fileloader[]', [ + 'value' => $item->file_id, + 'class' => 'fileloader-item-input', + ]) . Html::tag('p', Html::a($item->name, $item->dir, [ 'target' => '_blank' ]), [ + 'class' => 'fileloader-item-name', + ]) . Html::tag('span', '', [ + 'class' => 'fileloader-item-remove glyphicon glyphicon-remove', + ]) . '
'; + } + } + $this->list = Html::tag(ArrayHelper::remove($this->listOptions, 'tag', 'div'), $list, $this->listOptions); + } + } + + /** + * Fills template with components + * @return string + */ + public function renderLoader() + { + $template = $this->template; + $template = preg_replace('/{label}/', $this->label, $template); + $template = preg_replace('/{input}/', $this->input, $template); + $template = preg_replace('/{hint}/', $this->hint, $template); + $template = preg_replace('/{error}/', $this->error, $template); + $template = preg_replace('/{list}/', $this->list, $template); + if(empty( $this->options[ 'class' ] )) { + $this->options[ 'class' ] = $this->baseWrapperClass; + } else { + $this->options[ 'class' ] .= $this->baseWrapperClass; + } + return Html::tag(ArrayHelper::remove($this->options, 'tag', 'div'), $template, $this->options); + } + + /** + * Get already set items + * @return ActiveRecord[] + */ + public function getItems() + { + /** + * @var ActiveRecord $model + */ + $model = $this->model; + if($behavior = $model->getBehavior('fileloader')) { + if($behavior instanceof FileloaderBehavior) { + return $model->getFileloaderFiles() + ->all(); + } else { + return [ ]; + } + } else { + return [ ]; + } + } + + /** + * Render JS for widget + */ + public function renderJS() + { + /** + * @var View $view + */ + $view = $this->view; + $vars = json_encode([ + 'id' => $this->inputID, + 'model' => $this->model->className(), + ]); + $js = "if(fileloader === undefined) { + var fileloader = []; + fileloader[0] = " . $vars . "; + } else { + fileloader[fileloader.length] = " . $vars . "; + } + "; + $view->registerJs($js, $view::POS_BEGIN); + } + + } \ No newline at end of file diff --git a/console/migrations/m160325_153328_file_relation_table.php b/console/migrations/m160325_153328_file_relation_table.php new file mode 100644 index 0000000..0434e1b --- /dev/null +++ b/console/migrations/m160325_153328_file_relation_table.php @@ -0,0 +1,35 @@ +createTable('{{%file_relation}}', [ + 'file_relation_id' => $this->primaryKey(), + 'file_id' => $this->integer() + ->notNull(), + 'model' => $this->string() + ->notNull(), + 'model_id' => $this->integer() + ->notNull(), + 'user_id' => $this->integer(), + 'date_add' => $this->timestamp() + ->notNull() + ->defaultExpression('NOW()'), + 'status' => $this->smallInteger() + ->defaultValue(1), + ]); + $this->addForeignKey('file_relation_file', '{{%file_relation}}', 'file_id', '{{%file}}', 'file_id', 'CASCADE', 'CASCADE'); + $this->addForeignKey('file_relation_user', '{{%file_relation}}', 'user_id', '{{%user}}', 'id', 'SET NULL', 'CASCADE'); + } + + public function down() + { + $this->dropForeignKey('file_relation_file', '{{%file_relation}}'); + $this->dropForeignKey('file_relation_user', '{{%file_relation}}'); + $this->dropTable('{{%file_relation}}'); + } + } diff --git a/console/migrations/m160329_085324_file_add_user.php b/console/migrations/m160329_085324_file_add_user.php new file mode 100644 index 0000000..ed17714 --- /dev/null +++ b/console/migrations/m160329_085324_file_add_user.php @@ -0,0 +1,18 @@ +addColumn('{{%file}}', 'user_id', $this->integer()); + $this->addForeignKey('file_user', '{{%file}}', 'user_id', '{{%user}}', 'id', 'SET DEFAULT', 'CASCADE'); + } + + public function down() + { + $this->dropForeignKey('file_user', '{{%file}}'); + $this->dropColumn('{{%file}}', 'user_id'); + } +} diff --git a/frontend/controllers/SiteController.php b/frontend/controllers/SiteController.php index fee6be1..322272d 100755 --- a/frontend/controllers/SiteController.php +++ b/frontend/controllers/SiteController.php @@ -4,6 +4,7 @@ namespace frontend\controllers; use common\models\Cities; use common\models\CompanyInfo; use common\models\Country; +use common\models\Project; use common\models\Specialization; use common\models\UserInfo; use Faker\Provider\is_IS\Company; diff --git a/frontend/views/accounts/_projects_form.php b/frontend/views/accounts/_projects_form.php index 6fd8a38..d70f21a 100644 --- a/frontend/views/accounts/_projects_form.php +++ b/frontend/views/accounts/_projects_form.php @@ -7,10 +7,12 @@ */ use common\components\Request; use common\models\Currency; + use common\models\File; use common\models\Payment; use common\models\Project; use common\models\Specialization; use common\modules\file\widgets\ImageUploader; + use common\modules\fileloader\widgets\FileloaderWidget; use kartik\select2\Select2; use mihaildev\ckeditor\CKEditor; use yii\helpers\Html; @@ -24,7 +26,7 @@ ['enctype' => 'multipart/form-data']]); + $form = ActiveForm::begin([ 'options' => [ 'enctype' => 'multipart/form-data' ] ]); ?> @@ -212,43 +214,55 @@ -
- field($project, 'files[]') - ->fileInput([ 'class' => 'multi', 'multiple' => 'multiple' ]) - ->label(false) ?> - Прикрепить файл -
Максимальный размер
файла 5 МБ
-
- - -
-
-
-
Присоединить файл
-
Загрузить
-
До 3 Мб файл
-
-
- field($project, 'files[]') - ->fileInput([ 'multiple' => 'multiple' ]) ?> + /* == Old file upload == + ?> +
+
+
+
Присоединить файл
+
Загрузить
+
До 3 Мб файл
+
+
+ field($project, 'files[]') + ->fileInput([ 'multiple' => 'multiple' ]) ?> +
-
+ + +
+ field($project, 'fileloader') + ->label(false) + ->widget(FileloaderWidget::className(), [ + 'labelOptions' => [ 'label' => '
Присоединить файлы
Загрузить
До 3 Мб файл
' ], + 'inputOptions' => [ + 'multiple' => 'multiple', + 'class' => 'hidden', + ], + 'options' => [ 'class' => 'fileloader-file' ], + ]); + ?>
- field($project, 'date_end')->widget(DatePicker::className(), ['dateFormat' => 'yyyy-MM-dd', 'clientOptions' => ['minDate' => 1]]) ?> + field($project, 'date_end') + ->widget(DatePicker::className(), [ + 'dateFormat' => 'yyyy-MM-dd', + 'clientOptions' => [ 'minDate' => 1 ], + ]) ?>
- field($project, 'hidden')->checkbox()->hint('Проект, снятый с тендера, будет добавлен в Архив (не доступен в поиске, но доступен по ссылке)') ?> + field($project, 'hidden') + ->checkbox() + ->hint('Проект, снятый с тендера, будет добавлен в Архив (не доступен в поиске, но доступен по ссылке)') ?>
diff --git a/frontend/views/layouts/performer.php b/frontend/views/layouts/performer.php index 8911b1d..7991ca5 100755 --- a/frontend/views/layouts/performer.php +++ b/frontend/views/layouts/performer.php @@ -22,7 +22,7 @@ params[ 'user' ]->id != \Yii::$app->user->getId()) { // Offer project button - if(!empty( $this->params[ 'type' ] ) && $this->params[ 'type' ] == 'customer') { + if(empty( $this->params[ 'type' ] ) || $this->params[ 'type' ] != 'customer') { echo Html::a('Предложить проект', [ '#' ], [ 'class' => 'blog-buttons-offer', 'data-performer-id' => $this->params[ 'user' ]->id, diff --git a/frontend/views/site/index.php b/frontend/views/site/index.php index 0a35809..0c935d9 100755 --- a/frontend/views/site/index.php +++ b/frontend/views/site/index.php @@ -1,339 +1,312 @@ title = 'My Yii Application'; -?> + /** + * @var $this yii\web\View + * @var $specializations common\models\Specialization + */ -
-
-
-
- Самая полная база текущих и реализованных - строительных проектов с исполнителями -
-
-
- 'base-blocks-button first_butt']) ?> -
-

Лучшие компании и исполнители готовы помочь вам

-
+ $this->title = 'My Yii Application'; +?> +
+
+
+
+ Самая полная база текущих и реализованных + строительных проектов с исполнителями +
+
+
+ 'base-blocks-button first_butt' ]) ?> +
+

Лучшие компании и исполнители готовы помочь вам

-
- 'base-blocks-button second_butt']) ?> -
-

- Частные проекты и субподряды от лучших компаний и заказчиков для вас -

-

- - Вакансии компаний и заказчиков на полную занятость и резюме свободных проектантов -

-
+
+
+ 'base-blocks-button second_butt' ]) ?> +
+

+ Частные проекты и субподряды от лучших компаний и заказчиков для вас +

+

+ + Вакансии компаний и заказчиков на полную занятость и резюме свободных проектантов +

-
- 'base-blocks-button third_butt']) ?> -
-

Презентуйте лучшую команду профессиональных проектантов и получите актуальные тендеры на проектирование.

-
+
+
+ 'base-blocks-button third_butt' ]) ?> +
+

Презентуйте лучшую команду профессиональных проектантов и получите актуальные тендеры на проектирование.

-
-
-
- - +
+
+
+ + + + + +
-
-
-
-
-

Проекты на нашем сайте

-
    -
  • Текущие
  • -
  • Завершенные
  • -
-
+
+
+
+
+
+

Проекты на нашем сайте

+
    +
  • Текущие
  • +
  • Завершенные
  • +
-
-
- -
+ ]; + markerClusterer = new MarkerClusterer( + map, markers, { + maxZoom : 10, gridSize : 100, styles : clusterStyles + } + ); + } +
+
+
-
-
-
-
Зачем нужна Международная федерация проектантов
-
-
    -
  • Заказчикам
  • -
  • Компаниям
  • -
  • Проектантам
  • -
  • Наша миссия
  • -
-
-
-
-
-
-
Описания рейтингов
+
+
+
+
Зачем нужна Международная федерация проектантов
+
+
    +
  • Заказчикам
  • +
  • Компаниям
  • +
  • Проектантам
  • +
  • Наша миссия
  • +
+
+
+
+
+
-
-
-
Вы получаете лучшую цену
+
Описания рейтингов
+
+
+
-
-
-
Гарантии получения проекта в срок
+
Вы получаете лучшую цену
+
+
+
+
Гарантии получения проекта в срок
+
-
-
-
-
2Описания рейтингов
+
+
+
-
-
-
2Вы получаете лучшую цену
+
2Описания рейтингов
+
+
+
-
-
-
2Гарантии получения проекта в срок
+
2Вы получаете лучшую цену
+
+
+
+
2Гарантии получения проекта в срок
+
-
-
-
-
3Описания рейтингов
+
+
+
-
-
-
3Вы получаете лучшую цену
+
3Описания рейтингов
+
+
+
-
-
-
3Гарантии получения проекта в срок
+
3Вы получаете лучшую цену
+
+
+
+
3Гарантии получения проекта в срок
+
-
-
-
-
4Описания рейтингов
+
+
+
-
-
-
4Вы получаете лучшую цену
+
4Описания рейтингов
+
+
+
-
-
-
4Гарантии получения проекта в срок
+
4Вы получаете лучшую цену
+
+
+
+
4Гарантии получения проекта в срок
-
\ No newline at end of file +
+
\ No newline at end of file diff --git a/frontend/views/site/registration.php b/frontend/views/site/registration.php index a954158..c37a09d 100644 --- a/frontend/views/site/registration.php +++ b/frontend/views/site/registration.php @@ -117,7 +117,10 @@
- field($model, 'city', ['enableClientValidation' => false, 'options' => ['class' => 'required-no-star']]) + field($model, 'city', [ + 'enableClientValidation' => false, + 'options' => [ 'class' => 'required-no-star' ], + ]) ->widget(Select2::classname(), [ 'options' => [ 'placeholder' => 'Выбор города ...' ], 'pluginOptions' => [ @@ -199,9 +202,6 @@ $('.field-signupform-lastname label').html(labelLastName) $('.register-company-block').css('display', 'none'); $('#w0').yiiActiveForm('remove','signupform-name'); - - - } else { //company $('.field-signupform-firstname label').html(labelName+' '+newLabelName) diff --git a/frontend/web/css/style.css b/frontend/web/css/style.css index 59e8e3e..0967e73 100755 --- a/frontend/web/css/style.css +++ b/frontend/web/css/style.css @@ -6414,7 +6414,7 @@ input[disabled], select[disabled] { position: relative; height: 54px; } -.admin-project-file .admin-project-file-btn{ +.admin-project-file .admin-project-file-btn, .fileloader-file .admin-project-file-btn { background: #fff; color: #0072bc; height: 29px; @@ -6428,12 +6428,12 @@ input[disabled], select[disabled] { border-radius: 4px; cursor: pointer; } -.admin-project-file .admin-project-file-btn:hover{ +.admin-project-file .admin-project-file-btn:hover, .fileloader-file .admin-project-file-btn:hover{ transition: 0.2s; background: #0072bc; color: #fff; } -.admin-project-file .gen-admin-title{ +.admin-project-file .gen-admin-title, .fileloader-file .gen-admin-title{ font-size: 13px; font-weight: 700; margin-bottom: 10px; @@ -6444,7 +6444,7 @@ input[disabled], select[disabled] { cursor: pointer; margin-top: 8px; } -.admin-project-file .not-file-mb-adm{ +.admin-project-file .not-file-mb-adm, .fileloader-file .not-file-mb-adm { position: static; margin-left: 10px; width: 540px; -- libgit2 0.21.4