Commit 2d107e9e171d497711b3129ece88b25676c96a15

Authored by Yarik
1 parent d7d32bb2

test

common/config/main.php
... ... @@ -24,7 +24,10 @@
24 24 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field )
25 25 'targetMinPixel' => 200 // Target image minimum pixel size
26 26 ]
27   - ]
  27 + ],
  28 + 'artbox-comment' => [
  29 + 'class' => \common\modules\comment\Controller::className(),
  30 + ],
28 31 ],
29 32  
30 33 'modules' => [
... ...
common/models/Blog.php
... ... @@ -87,8 +87,6 @@
87 87 return date('Y-m-d',strtotime($this->date_add));
88 88 }
89 89  
90   -
91   -
92 90 /**
93 91 * @inheritdoc
94 92 */
... ...
common/modules/comment/Controller.php 0 → 100644
  1 +<?php
  2 + namespace common\modules\comment;
  3 +
  4 + class Controller extends \yii\web\Controller
  5 + {
  6 + public function behaviors()
  7 + {
  8 + return [
  9 + 'verbs' => [
  10 + 'class' => \yii\filters\VerbFilter::className(),
  11 + 'actions' => [
  12 + '*' => ['post'],
  13 + ],
  14 + ],
  15 + ];
  16 + }
  17 +
  18 + public function actionDelete()
  19 + {
  20 + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  21 + $post = \Yii::$app->request->post('Comment');
  22 + if(!empty($post['comment_id'])) {
  23 + if($model = \common\modules\comment\models\Comment::findOne($post['comment_id'])) {
  24 + /**
  25 + * @var \common\modules\comment\models\Comment $model
  26 + */
  27 + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST;
  28 + if($model->deleteComment()) {
  29 + \Yii::$app->response->data = ['text' => 'Comment marked as deleted and will be check by administrators'];
  30 + } else {
  31 + \Yii::$app->response->data = ['error' => $model->hasErrors('comment_id')?$model->getFirstError('comment_id'):'Cannot delete message'];
  32 + }
  33 + }else {
  34 + \Yii::$app->response->data = ['error' => 'Comment not found'];
  35 + };
  36 + } else {
  37 + \Yii::$app->response->data = ['error' => 'Missing comment_id'];
  38 + }
  39 + \Yii::$app->response->send();
  40 + }
  41 +
  42 + public function actionUpdate()
  43 + {
  44 + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  45 + $post = \Yii::$app->request->post();
  46 + if(!empty($post['Comment']['comment_id'])) {
  47 + if($model = \common\modules\comment\models\Comment::findOne($post['Comment']['comment_id'])) {
  48 + /**
  49 + * @var \common\modules\comment\models\Comment $model
  50 + */
  51 + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST;
  52 + $model->load($post);
  53 + if(empty($post['Comment']['comment_pid'])) {
  54 + $model->comment_pid = null;
  55 + }
  56 + if($model->updateComment()) {
  57 + \Yii::$app->response->data = ['text' => 'Comment successfully updated'];
  58 + } else {
  59 + \Yii::$app->response->data = ['error' => $model->hasErrors()?$model->getFirstErrors():'Cannot update message'];
  60 + }
  61 + }else {
  62 + \Yii::$app->response->data = ['error' => 'Comment not found'];
  63 + };
  64 + } else {
  65 + \Yii::$app->response->data = ['error' => 'Missing comment_id'];
  66 + }
  67 + \Yii::$app->response->send();
  68 + }
  69 +
  70 + public function actionForm()
  71 + {
  72 + $post = \Yii::$app->request->post('Comment');
  73 + if(!empty($post['comment_id'])) {
  74 + $model = \common\modules\comment\models\Comment::find()->where(['comment_id' => $post['comment_id']])->with('parent', 'author')->one();
  75 + if($model) {
  76 + /**
  77 + * @var \common\modules\comment\models\Comment $model
  78 + */
  79 + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST;
  80 + if($model->checkUpdate()) {
  81 + return $this->renderAjax('@common/modules/comment/views/comment_form', [
  82 + 'model' => $model,
  83 + ]);
  84 + } else {
  85 + \Yii::$app->response->data = ['error' => 'You are not able to update this comment'];
  86 + }
  87 + }else {
  88 + \Yii::$app->response->data = ['error' => 'Comment not found'];
  89 + };
  90 + } else {
  91 + \Yii::$app->response->data = ['error' => 'Missing comment_id'];
  92 + }
  93 + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  94 + \Yii::$app->response->send();
  95 + }
  96 + }
0 97 \ No newline at end of file
... ...
common/modules/comment/Permissions.php
... ... @@ -8,5 +8,5 @@
8 8 const UPDATE = 'artbox_comment.update';
9 9 const DELETE = 'artbox_comment.delete';
10 10 const UPDATE_OWN = 'artbox_comment.update_own';
11   - const DELETE_OWN = 'artbox_comment.delete.own';
  11 + const DELETE_OWN = 'artbox_comment.delete_own';
12 12 }
13 13 \ No newline at end of file
... ...
common/modules/comment/assets/CommentAsset.php 0 → 100644
  1 +<?php
  2 + namespace common\modules\comment\assets;
  3 +
  4 + class CommentAsset extends \yii\web\AssetBundle
  5 + {
  6 + public $sourcePath = '@common/modules/comment/resources';
  7 +
  8 + public $css = [
  9 + 'comment.css',
  10 + ];
  11 +
  12 + public $js = [
  13 + 'comment.js',
  14 + ];
  15 +
  16 + public $depends = [
  17 + '\yii\web\YiiAsset',
  18 + '\yii\web\JqueryAsset',
  19 + ];
  20 +
  21 + }
0 22 \ No newline at end of file
... ...
common/modules/comment/interfaces/CommentInterface.php
... ... @@ -5,7 +5,7 @@
5 5 public function load($data, $formName = null);
6 6 public function formName();
7 7 public function getComments($entity);
8   - public function postComment($data);
9   - public function deleteComment($comment_id);
10   - public function updateComment($comment_id);
  8 + public function postComment();
  9 + public function deleteComment();
  10 + public function updateComment();
11 11 }
... ...
common/modules/comment/models/Comment.php
... ... @@ -3,7 +3,8 @@
3 3  
4 4 /**
5 5 * Class Comment
6   - * @property bool $guestComment
  6 + * @property bool $guestComment
  7 + * @property integer $comment_id
7 8 * @package common\modules\comment\models
8 9 */
9 10 class Comment extends \yii\db\ActiveRecord
... ... @@ -18,29 +19,87 @@
18 19 const SCENARIO_USER = 'user';
19 20 const SCENARIO_GUEST = 'guest';
20 21  
  22 + /**
  23 + * @var bool
  24 + */
  25 + public $guestComment = true;
  26 +
21 27 public function rules()
22 28 {
23 29 return [
24 30 [
25   - ['text'],
  31 + [
  32 + 'text',
  33 + 'user_name',
  34 + 'user_email',
  35 + ],
26 36 'required',
27 37 ],
28 38 [
29   - ['user_email'],
  39 + [
  40 + 'rating',
  41 + ],
  42 + 'safe',
  43 + ],
  44 + [
  45 + [ 'user_email' ],
30 46 'email',
31 47 ],
32 48 [
33   - ['user_name'],
  49 + [ 'user_name' ],
34 50 'string',
35 51 ],
  52 + [
  53 + [
  54 + 'comment_id',
  55 + 'comment_pid',
  56 + ],
  57 + 'integer',
  58 + ],
  59 + [
  60 + [ 'status' ],
  61 + 'default',
  62 + 'value' => 1,
  63 + ],
  64 + [
  65 + [ 'comment_pid' ],
  66 + 'exist',
  67 + 'targetAttribute' => 'comment_id',
  68 + 'filter' => [
  69 + 'entity' => $this->entity,
  70 + ],
  71 + ],
36 72 ];
37 73 }
38 74  
39 75 public function scenarios()
40 76 {
41 77 return [
42   - self::SCENARIO_GUEST => ['user_name', 'user_email', 'text'],
43   - self::SCENARIO_USER => ['text'],
  78 + self::SCENARIO_GUEST => [
  79 + 'user_name',
  80 + 'user_email',
  81 + 'text',
  82 + 'comment_pid',
  83 + ],
  84 + self::SCENARIO_USER => [
  85 + 'text',
  86 + 'comment_pid',
  87 + ],
  88 + ];
  89 + }
  90 +
  91 + /**
  92 + * @inheritdoc
  93 + */
  94 + public function behaviors()
  95 + {
  96 + return [
  97 + [
  98 + 'class' => \yii\behaviors\TimestampBehavior::className(),
  99 + 'createdAtAttribute' => 'date_add',
  100 + 'updatedAtAttribute' => 'date_update',
  101 + 'value' => new \yii\db\Expression('NOW()'),
  102 + ],
44 103 ];
45 104 }
46 105  
... ... @@ -55,52 +114,119 @@
55 114 public function attributeLabels()
56 115 {
57 116 return [
58   - 'text' => \Yii::t('app', 'Комментарий'),
59   - 'user_name' => \Yii::t('app', 'Имя'),
  117 + 'text' => \Yii::t('app', 'Комментарий'),
  118 + 'user_name' => \Yii::t('app', 'Имя'),
60 119 'user_email' => \Yii::t('app', 'Email'),
61 120 ];
62 121 }
63 122  
64   - public function getGuestComment($entity)
  123 + public function getGuestComment()
  124 + {
  125 + return $this->guestComment;
  126 + }
  127 +
  128 + public function setGuestComment($value)
65 129 {
66   - return true;
  130 + $this->guestComment = $value;
67 131 }
68 132  
69 133 public function getComments($entity)
70 134 {
71   - return $this->find()->where(['entity' => $this->entity]);
  135 + return $this->find()
  136 + ->where([
  137 + 'entity' => $this->entity,
  138 + 'status' => 1,
  139 + ]);
72 140 }
73 141  
74   - public function postComment($data)
  142 + public function postComment()
75 143 {
76   - if($this->load($data) && $this->insert($data)) {
77   - $this->clearSafe();
78   - return true;
  144 + if($this->checkCreate()) {
  145 + if($this->insert()) {
  146 + $this->clearSafe();
  147 + return true;
  148 + } else {
  149 + return false;
  150 + }
79 151 } else {
  152 + $this->addError('comment_id', 'You can`t post comment here');
80 153 return false;
81 154 }
82 155 }
83 156  
84   - public function updateComment($comment_id)
  157 + public function updateComment()
85 158 {
86   - // TODO: Implement updateComment() method.
  159 + if($this->checkUpdate()) {
  160 + if(empty( $this->comment_id )) {
  161 + $this->addError('comment_id', 'Comment ID not found');
  162 + return false;
  163 + } else {
  164 + if($this->update()) {
  165 + $this->clearSafe();
  166 + return true;
  167 + } else {
  168 + return false;
  169 + }
  170 + }
  171 + } else {
  172 + $this->addError('comment_id', 'You can`t update this post');
  173 + return false;
  174 + }
87 175 }
88 176  
89   - public function deleteComment($comment_id)
  177 + public function deleteComment()
90 178 {
91   - // TODO: Implement deleteComment() method.
  179 + if($this->checkDelete()) {
  180 + if(empty( $this->comment_id )) {
  181 + $this->addError('comment_id', 'Comment ID not found');
  182 + return false;
  183 + } else {
  184 + if($this->status == self::STATUS_DELETED) {
  185 + return false;
  186 + }
  187 + $this->status = self::STATUS_DELETED;
  188 + if($this->update()) {
  189 + $this->clearSafe();
  190 + return true;
  191 + } else {
  192 + return false;
  193 + }
  194 + }
  195 + } else {
  196 + $this->addError('comment_id', 'You can`t delete this post');
  197 + return false;
  198 + }
92 199 }
93 200  
94   - public function checkCreate($entity)
  201 + public function checkCreate()
95 202 {
96   - if($this->getGuestComment($entity)) {
  203 + if($this->getGuestComment()) {
97 204 return true;
98 205 } else {
99   - return \Yii::$app->user->can(\common\modules\comment\Permissions::CREATE, ['entity' => $entity]);
  206 + return \Yii::$app->user->can(\common\modules\comment\Permissions::CREATE, [ 'entity' => $this->entity ]);
100 207 }
101 208 }
102 209  
103   - protected function clearSafe($setNew = true) {
  210 + public function checkUpdate()
  211 + {
  212 + if($this->scenario == self::SCENARIO_GUEST) {
  213 + return false;
  214 + } else {
  215 + return \Yii::$app->user->can(\common\modules\comment\Permissions::UPDATE, [ 'entity' => $this->entity ]) || \Yii::$app->user->can(\common\modules\comment\Permissions::UPDATE_OWN, [ 'entity' => $this->entity ]);
  216 + }
  217 + }
  218 +
  219 + public function checkDelete()
  220 + {
  221 + if($this->scenario == self::SCENARIO_GUEST) {
  222 + return false;
  223 + } else {
  224 + return \Yii::$app->user->can(\common\modules\comment\Permissions::DELETE, [ 'entity' => $this->entity ]) || \Yii::$app->user->can(\common\modules\comment\Permissions::DELETE_OWN, [ 'entity' => $this->entity ]);
  225 + }
  226 + }
  227 +
  228 + protected function clearSafe($setNew = true)
  229 + {
104 230 $safe = $this->safeAttributes();
105 231 $count = count($safe);
106 232 $values = array_fill(0, $count, NULL);
... ... @@ -109,4 +235,56 @@
109 235 $this->setIsNewRecord($setNew);
110 236 }
111 237  
112   - }
113 238 \ No newline at end of file
  239 + public function getParent()
  240 + {
  241 + return $this->hasOne(self::className(), [ 'comment_id' => 'comment_pid' ]);
  242 + }
  243 +
  244 + public function getAuthor()
  245 + {
  246 + // if($this->user_id != NULL) {
  247 + return $this->hasOne(\common\models\User::className(), [ 'id' => 'user_id' ]);
  248 + // } else {
  249 + // return ['firstname' => $this->user_name, 'email' => $this->user_email];
  250 + // }
  251 + }
  252 +
  253 + public function checkRating()
  254 + {
  255 + $rating = $this->hasOne(\common\modules\comment\models\Rating::className(), [ 'entity' => 'entityId' ])
  256 + ->one();
  257 + if(!$rating instanceof \common\modules\comment\models\Rating) {
  258 + $rating = new \common\modules\comment\models\Rating([
  259 + 'entity' => $this->entityId,
  260 + 'user_id' => $this->user_id,
  261 + ]);
  262 + $rating->save();
  263 + }
  264 + }
  265 +
  266 + public function getRating()
  267 + {
  268 + $this->checkRating();
  269 + return $this->hasOne(\common\modules\comment\models\Rating::className(), [ 'entity' => 'entityId' ]);
  270 + }
  271 +
  272 + public function hasRating($return = true)
  273 + {
  274 + $rating = $this->hasOne(\common\modules\comment\models\Rating::className(), [ 'entity' => 'entityId' ])
  275 + ->andWhere([
  276 + 'not',
  277 + [ 'value' => NULL ],
  278 + ])
  279 + ->one();
  280 + if($return) {
  281 + return $rating;
  282 + } else {
  283 + return $rating ? true : false;
  284 + }
  285 + }
  286 +
  287 + public function getEntityId()
  288 + {
  289 + return $this->formName() . '-' . $this->getPrimaryKey();
  290 + }
  291 + }
... ...
common/modules/comment/models/Rating.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace common\modules\comment\models;
  4 +
  5 +use Yii;
  6 +
  7 +/**
  8 + * This is the model class for table "rating".
  9 + *
  10 + * @property integer $rating_id
  11 + * @property string $date_add
  12 + * @property string $date_update
  13 + * @property integer $user_id
  14 + * @property string $entity
  15 + * @property integer $value
  16 + *
  17 + * @property \common\models\User $user
  18 + */
  19 +class Rating extends \yii\db\ActiveRecord
  20 +{
  21 + /**
  22 + * @inheritdoc
  23 + */
  24 + public static function tableName()
  25 + {
  26 + return 'rating';
  27 + }
  28 +
  29 + /**
  30 + * @inheritdoc
  31 + */
  32 + public function rules()
  33 + {
  34 + return [
  35 + [['value'], 'integer'],
  36 + ];
  37 + }
  38 +
  39 + /**
  40 + * @inheritdoc
  41 + */
  42 + public function attributeLabels()
  43 + {
  44 + return [
  45 + 'rating_id' => Yii::t('app', 'Rating ID'),
  46 + 'date_add' => Yii::t('app', 'Date Add'),
  47 + 'date_update' => Yii::t('app', 'Date Update'),
  48 + 'user_id' => Yii::t('app', 'User ID'),
  49 + 'entity' => Yii::t('app', 'Entity'),
  50 + 'value' => Yii::t('app', 'Value'),
  51 + ];
  52 + }
  53 +
  54 + /**
  55 + * @return \yii\db\ActiveQuery
  56 + */
  57 + public function getUser()
  58 + {
  59 + return $this->hasOne(\common\models\User::className(), ['id' => 'user_id']);
  60 + }
  61 +}
... ...
common/modules/comment/resources/comment.css 0 → 100644
  1 +.artbox_comment_reply_author, .artbox_comment_update_reply {
  2 + position: relative;
  3 + width: 25%;
  4 +}
  5 +.artbox_comment_update_reply {
  6 + width: 25%;
  7 + float: none;
  8 +}
  9 +.artbox_comment_reply_author:after, .artbox_comment_update_reply:after {
  10 + content: '';
  11 + background-image: url('delete-ico.png');
  12 + display: block;
  13 + position: absolute;
  14 + right: -13px;
  15 + width: 13px;
  16 + height: 13px;
  17 + top: 0;
  18 + cursor: pointer;
  19 +}
0 20 \ No newline at end of file
... ...
common/modules/comment/resources/comment.js 0 → 100644
  1 +$(function() {
  2 +
  3 + $(document).on('click', '.artbox_comment_delete', function() {
  4 + var container = $(this).parents('.artbox_comment_container');
  5 + var comment_id = $(container).data('comment_id');
  6 + var form_name = $(container).data('form_name');
  7 + if(confirm("Уверены, что хотите удалить комментарий?")) {
  8 + $.post(
  9 + '/artbox-comment/delete',
  10 + {
  11 + Comment: {
  12 + comment_id: comment_id
  13 + }
  14 + },
  15 + function(data, textStatus, jqXHR) {
  16 + if(!data.error) {
  17 + $(container).after('<p class="removeable">'+data.text+'</p>');
  18 + $(container).remove();
  19 + } else {
  20 + $(container).prepend('<p class="removeable error_message">'+data.error+'</p>')
  21 + }
  22 + }
  23 + );
  24 + }
  25 + });
  26 +
  27 + $(document).on('click', '.artbox_comment_reply', function() {
  28 + var container = $(this).parents('.artbox_comment_container').first();
  29 + var comment_id = $(container).data('comment_id');
  30 + var form_name = $(container).data('form_name');
  31 + var author = $(container).find('.artbox_comment_author').first().text();
  32 + var comment_form = $('.artbox_comment_form').first();
  33 + var offset = $(comment_form).offset();
  34 + var reply_block = $(comment_form).find('.artbox_comment_reply_block').first();
  35 + $(reply_block).empty();
  36 + $(reply_block).append('<input type="hidden" name="'+form_name+'[comment_pid]" value="'+comment_id+'">');
  37 + $(reply_block).append('<p class="artbox_comment_reply_author">'+author+'</p>');
  38 + $('html, body').animate({
  39 + scrollTop: offset.top - 50,
  40 + });
  41 + });
  42 +
  43 + $(document).on('click', '.artbox_comment_reply_author', function() {
  44 + $(this).parents('.artbox_comment_reply_block').first().empty();
  45 + });
  46 +
  47 + $(document).on('click', '.artbox_comment_update', function() {
  48 + $(this).removeClass('artbox_comment_update');
  49 + $(this).text('Сохранить');
  50 + $(this).addClass('artbox_comment_update_submit');
  51 + var container = $(this).parents('.artbox_comment_container').first();
  52 + var comment_id = $(container).data('comment_id');
  53 + var form_name = $(container).data('form_name');
  54 + var text = $(container).find('.artbox_comment_text');
  55 + var object = {};
  56 + object[form_name] = {comment_id: comment_id};
  57 + $.post(
  58 + '/artbox-comment/form',
  59 + object,
  60 + function(data, textStatus, jqXHR) {
  61 + $(text).hide();
  62 + $(text).after(
  63 + '<div class="artbox_comment_text_edit new-portf-answer">'
  64 + + data
  65 + + '</div>'
  66 + );
  67 + }
  68 + );
  69 + });
  70 +
  71 + $(document).on('click', '.artbox_comment_update_reply', function() {
  72 + $(this).remove();
  73 + });
  74 +
  75 + $(document).on('click', '.artbox_comment_update_submit', function(e) {
  76 + e.preventDefault();
  77 + var container = $(this).parents('.artbox_comment_container').first();
  78 + var edit = $(container).find('.artbox_comment_text_edit').first();
  79 + $.post(
  80 + '/artbox-comment/update',
  81 + $(edit).find('form').serialize(),
  82 + function(data) {
  83 + if(!data.error) {
  84 + location.reload(true);
  85 + }
  86 + }
  87 + )
  88 + });
  89 +});
0 90 \ No newline at end of file
... ...
common/modules/comment/resources/delete-ico.png 0 → 100644

368 Bytes

common/modules/comment/views/comment_form.php 0 → 100644
  1 +<?php
  2 + /**
  3 + * @var \common\modules\comment\models\Comment $model
  4 + */
  5 + use yii\widgets\ActiveForm;
  6 +
  7 + $form = ActiveForm::begin();
  8 +
  9 +?>
  10 +<?php
  11 + echo $form->field($model, 'comment_id')
  12 + ->label(false)
  13 + ->hiddenInput();
  14 + if(!empty( $model->parent )) {
  15 + ?>
  16 + <div class="artbox_comment_update_reply">
  17 + <?php
  18 + echo "<span>";
  19 + if(!empty( $model->parent->author )) {
  20 + echo $model->parent->author->firstname . ' ' . $model->parent->author->lastname;
  21 + } else {
  22 + echo $model->parent->user_name;
  23 + }
  24 + echo "</span>";
  25 + echo $form->field($model, 'comment_pid')
  26 + ->label(false)
  27 + ->hiddenInput();
  28 + ?>
  29 + </div>
  30 + <?php
  31 + }
  32 + echo $form->field($model, 'text')
  33 + ->label(false)
  34 + ->textarea();
  35 +?>
  36 +<?php
  37 + $form->end();
  38 +?>
0 39 \ No newline at end of file
... ...
common/modules/comment/widgets/CommentWidget.php
... ... @@ -8,9 +8,18 @@
8 8 {
9 9  
10 10 /**
  11 + * @var null|\yii\web\View
  12 + */
  13 + public $context = NULL;
  14 +
  15 + /**
11 16 * @var array Parts of widgets that can be rendered
12 17 */
13   - public $parts = [];
  18 + public $parts = [ ];
  19 +
  20 + public $rating_class = NULL;
  21 +
  22 + public $rating_options = [ ];
14 23  
15 24 /**
16 25 * @var string|\common\modules\comment\models\Comment
... ... @@ -20,7 +29,7 @@
20 29 /**
21 30 * @var array
22 31 */
23   - public $class_options = [];
  32 + public $class_options = [ ];
24 33  
25 34 /**
26 35 * @var bool Wheather to display comment list
... ... @@ -28,44 +37,72 @@
28 37 public $display_comment_list = true;
29 38  
30 39 /**
31   - * @var bool Wheather to display comment form
  40 + * @var bool Whether to display comment form
32 41 */
33 42 public $display_comment_form = true;
34 43  
  44 + /**
  45 + * @var bool Whether to display success text
  46 + */
35 47 public $display_comment_success = true;
36 48  
  49 + /**
  50 + * @var bool Whether to allow one user post multiple comments
  51 + */
37 52 public $allow_multiple = true;
38 53  
39   - public $success_text = "Comment posted successfully";
40   -
  54 + /**
  55 + * @var array Options sent to list part
  56 + */
41 57 public $list_options = [
42   - 'tag' => 'div',
43   - 'view' => 'list-comment',
  58 + 'tag' => 'div',
  59 + 'view' => 'list-comment',
44 60 'class' => 'test-class',
45 61 ];
46 62  
  63 + /**
  64 + * @var array Options sent to success part
  65 + */
47 66 public $success_options = [
48   - 'tag' => 'div',
49   - 'content' => null,
50   - 'class' => 'test-class-success',
  67 + 'tag' => 'div',
  68 + 'content' => NULL,
  69 + 'class' => 'test-class-success',
51 70 ];
52 71  
  72 + /**
  73 + * @var array Options sent to form part
  74 + */
53 75 public $form_options = [
54   - 'tag' => 'div',
55   - 'view' => 'form-comment',
  76 + 'tag' => 'div',
  77 + 'view' => 'form-comment',
56 78 'class' => 'test-class-form',
57 79 ];
58 80  
  81 + /**
  82 + * @var bool Indicates whether any successful action happened
  83 + */
59 84 protected $isSuccess = false;
60 85  
  86 + public $success_text = 'Comment successfully added';
  87 +
  88 + /**
  89 + * @var string Entity, to which comments attached
  90 + */
61 91 public $entity;
62 92  
  93 + /**
  94 + * @var string Template of the widget. You may use <code>{success}, {form}, {list}</code>
  95 + * to render particular parts. You are also able to use common HTML here.
  96 + */
63 97 public $template = "{success}\n{form}\n{list}";
64 98  
65   - public $options = [];
  99 + /**
  100 + * @var array Widget options
  101 + */
  102 + public $options = [ ];
66 103  
67 104 /**
68   - * @var \yii\data\DataProviderInterface
  105 + * @var \yii\data\DataProviderInterface Data provider of comments
69 106 */
70 107 public $dataProvider;
71 108  
... ... @@ -75,16 +112,20 @@
75 112 public function init()
76 113 {
77 114 parent::init();
  115 + \common\modules\comment\assets\CommentAsset::register($this->view);
78 116 if(is_string($this->comment_class)) {
79 117 $this->comment_class = new $this->comment_class($this->class_options);
80   - } elseif(!is_object($this->comment_class)) {
81   - throw new \yii\base\InvalidConfigException(__CLASS__.'->comment_class must be defined as string or object.');
  118 + } else {
  119 + throw new \yii\base\InvalidConfigException(__CLASS__ . '->comment_class must be defined as object full class name string.');
  120 + }
  121 + if(!empty( $this->rating_class ) && is_string($this->rating_class)) {
  122 + $this->rating_class = new $this->rating_class($this->rating_options);
  123 + } elseif(!empty( $this->rating_class )) {
  124 + throw new \yii\base\InvalidConfigException(__CLASS__ . '->rating_class must be defined as object full class name string.');
82 125 }
83 126 $this->comment_class->entity = $this->entity;
84 127 $this->createDataProvider();
85   - if($this->comment_class->checkCreate($this->entity)) {
86   - $this->handleCreate();
87   - }
  128 + $this->process();
88 129 ob_start();
89 130 }
90 131  
... ... @@ -99,62 +140,67 @@
99 140 return $this->renderWidget();
100 141 }
101 142  
102   - public function createParts() {
  143 + public function createParts()
  144 + {
103 145 if($this->display_comment_success && $this->isSuccess) {
104 146 $tag = ArrayHelper::remove($this->success_options, 'tag', 'div');
105   - if(is_callable($this->success_options['content'])) {
  147 + if(is_callable($this->success_options[ 'content' ])) {
106 148 $result = call_user_func(ArrayHelper::remove($this->success_options, 'content'), $this->success_text);
107   - } elseif($this->success_options['content'] != NULL) {
  149 + } elseif($this->success_options[ 'content' ] != NULL) {
108 150 $result = Html::encode(ArrayHelper::remove($this->success_options, 'content', $this->success_text));
109 151 } else {
110 152 $result = Html::encode($this->success_text);
111 153 }
112   - $this->parts['success'] = Html::tag($tag, $result, $this->success_options);
113   - unset($tag, $result);
  154 + $this->parts[ 'success' ] = Html::tag($tag, $result, $this->success_options);
  155 + unset( $tag, $result );
114 156 }
115 157  
116 158 if($this->display_comment_list) {
117 159 $tag = ArrayHelper::remove($this->list_options, 'tag', 'div');
118 160 $view = ArrayHelper::remove($this->list_options, 'view');
119   - $this->parts['list'] = Html::tag($tag, $this->renderItems($view), $this->list_options);
  161 + $this->parts[ 'list' ] = Html::tag($tag, $this->renderItems($view), $this->list_options);
120 162 }
121 163  
122 164 if($this->display_comment_form) {
123 165 $tag = ArrayHelper::remove($this->form_options, 'tag', 'div');
124 166 $view = ArrayHelper::remove($this->form_options, 'view');
125   - $this->parts['form'] = Html::tag($tag, $this->renderForm($view), $this->list_options);
  167 + $this->parts[ 'form' ] = Html::tag($tag, $this->renderForm($view), $this->form_options);
126 168 }
127 169 }
128 170  
129 171 public function createDataProvider()
130 172 {
131 173 $this->dataProvider = new \yii\data\ActiveDataProvider([
132   - 'query' => $this->comment_class->getComments($this->entity),
  174 + 'query' => $this->comment_class->getComments($this->entity),
133 175 'pagination' => [
134 176 'pageSize' => 10,
135 177 ],
136 178 ]);
137 179 }
138 180  
139   - public function renderItems($view) {
140   - if(empty($view)) {
  181 + public function renderItems($view)
  182 + {
  183 + if(empty( $view )) {
141 184 throw new \yii\base\InvalidConfigException("list_options[view] must be set");
142 185 }
143   - return $this->render($view, ['dataProvider' => $this->dataProvider]);
  186 + return $this->render($view, [ 'dataProvider' => $this->dataProvider ]);
144 187 }
145 188  
146   - public function renderForm($view) {
147   - if(empty($view)) {
  189 + public function renderForm($view)
  190 + {
  191 + if(empty( $view )) {
148 192 throw new \yii\base\InvalidConfigException("form_options[view] must be set");
149 193 }
150 194 return $this->render($view, [
151   - 'model' => $this->comment_class,
152   - 'user' => \Yii::$app->user->identity,
  195 + 'model' => $this->comment_class,
  196 + 'rating' => $this->rating_class,
  197 + 'user' => \Yii::$app->user->identity,
153 198 'dataProvider' => $this->dataProvider,
154 199 ]);
155 200 }
156 201  
157   - public function renderWidget() {
  202 + public function renderWidget()
  203 + {
158 204 $template = $this->template;
159 205 $parts = $this->parts;
160 206 $options = $this->options;
... ... @@ -165,11 +211,13 @@
165 211 return Html::tag($tag, $template, $options);
166 212 }
167 213  
168   - public function handleCreate()
  214 + public function process()
169 215 {
170 216 $data = \Yii::$app->request->post();
171   - if($this->comment_class->postComment($data)) {
172   - $this->isSuccess = true;
173   - };
  217 + if($this->comment_class->load($data) && $this->comment_class->postComment()) {
  218 + if(is_object($this->rating_class) && $this->comment_class->rating->load($data) && $this->comment_class->rating->save()) {
  219 + $this->isSuccess = true;
  220 + }
  221 + }
174 222 }
175 223 }
176 224 \ No newline at end of file
... ...
common/modules/comment/widgets/views/form-comment.php
1 1 <?php
2 2 /**
3   - * @var \common\modules\comment\models\Comment $model
4   - * @var \common\models\User $user
5   - * @var \yii\data\ActiveDataProvider $dataProvider
  3 + * @var \common\modules\comment\models\Comment $model
  4 + * @var \common\models\User $user
  5 + * @var \yii\data\ActiveDataProvider $dataProvider
  6 + * @var null|\common\modules\comment\models\Rating $rating
6 7 */
7 8 use yii\widgets\ActiveForm;
8 9 use yii\helpers\Html;
... ... @@ -11,42 +12,59 @@
11 12 <div class="new-portf-comm-count">Комментарии: <?= $dataProvider->totalCount ?></div>
12 13  
13 14 <div class="new-portf-add-comm style">
  15 +
14 16 <?php
15 17 $form = ActiveForm::begin();
16   - ?>
17 18  
18   - <?php
  19 + echo $form->field($rating, 'value')
  20 + ->label(false)
  21 + ->radioList([
  22 + 1 => 1,
  23 + 2 => 2,
  24 + 3 => 3,
  25 + 4 => 4,
  26 + 5 => 5,
  27 + ]);
  28 +
19 29 if($model->scenario == $model::SCENARIO_GUEST) {
20 30 echo $form->field($model, 'user_name', [
21   - 'options' => [
  31 + 'options' => [
22 32 'class' => 'input-blocks-comm',
23 33 ],
24 34 'inputOptions' => [
25 35 'class' => 'custom-input-4',
26 36 ],
27   - ])->textInput();
  37 + ])
  38 + ->textInput();
28 39 echo $form->field($model, 'user_email', [
29   - 'options' => [
  40 + 'options' => [
30 41 'class' => 'input-blocks-comm',
31 42 ],
32 43 'inputOptions' => [
33 44 'class' => 'custom-input-4',
34 45 ],
35   - ])->textInput();
  46 + ])
  47 + ->textInput();
36 48 }
  49 +
  50 + ?>
  51 + <div class="artbox_comment_reply_block"></div>
  52 + <?php
  53 +
37 54 echo $form->field($model, 'text', [
38   - 'options' => [
  55 + 'options' => [
39 56 'class' => 'input-blocks-comm area-comm',
40 57 ],
41 58 'inputOptions' => [
42 59 'class' => 'custom-area-4',
43 60 ],
44   - ])->textarea();
  61 + ])
  62 + ->textarea();
45 63 ?>
46   - <div class="input-blocks-comm-button style">
47   - <?= Html::submitButton('Добавить комментарий') ?>
48   - </div>
49   - <?php
  64 + <div class="input-blocks-comm-button style">
  65 + <?= Html::submitButton('Добавить комментарий') ?>
  66 + </div>
  67 + <?php
50 68 $form->end();
51 69 ?>
52 70 </div>
53 71 \ No newline at end of file
... ...
common/modules/comment/widgets/views/project_comment_view.php
... ... @@ -3,9 +3,9 @@
3 3 use yii\helpers\Html;
4 4  
5 5 /**
6   - * @var \common\modules\comment\models\Comment $model Current comment model
7   - * @var integer $key ID of current comment
8   - * @var integer $index index of current element according to
  6 + * @var \common\modules\comment\models\Comment $model Current comment model
  7 + * @var integer $key ID of current comment
  8 + * @var integer $index index of current element according to
9 9 * current page, starting from 0
10 10 * @var \yii\widgets\ListView $widget current ListView instance
11 11 * @var User $user
... ... @@ -18,7 +18,7 @@
18 18 ->one();
19 19 }
20 20 ?>
21   -<div class="new-portf-comm-read">
  21 +<div class="new-portf-comm-read artbox_comment_container" data-comment_id="<?= $model->comment_id ?>" data-form_name="<?= $model->formName() ?>">
22 22 <div class="style">
23 23 <div class="header-cabinet-foto">
24 24 <?php
... ... @@ -32,23 +32,29 @@
32 32 <div class="new-prof-wrapper-read">
33 33 <div class="new-portf-comm-read-title">
34 34 <?php
35   - if(!empty($user)) {
36   - echo Html::a($user->firstname . ' ' . $user->lastname, [
37   - 'performer/common',
38   - 'performer_id' => $user->id,
39   - ]);
40   - } else {
41   - echo $model->user_name . '(Гость)';
42   - }
  35 + if(!empty( $user )) {
  36 + echo Html::a('<span class="artbox_comment_author">' . $user->firstname . ' ' . $user->lastname . '</span>', [
  37 + 'performer/common',
  38 + 'performer_id' => $user->id,
  39 + ]);
  40 + } else {
  41 + echo '<span class="artbox_comment_author">' . $model->user_name . '</span>' . '(Гость)';
  42 + }
43 43 ?>
44 44 </div>
45 45 <div class="new-portf-comm-read-rating">
46   - <div class="rating">
47   - <!--оценка-->
48   - <input type="hidden" class="val" value="3"/>
49   - <!--количество голосов-->
50   - <input type="hidden" class="votes" value="12"/>
51   - </div>
  46 + <?php
  47 + if($rating = $model->hasRating()) {
  48 + ?>
  49 + <div class="rating">
  50 + <!--оценка-->
  51 + <input type="hidden" class="val" value="<?= $rating->value ?>"/>
  52 + <!--количество голосов-->
  53 + <input type="hidden" class="votes" value="1"/>
  54 + </div>
  55 + <?php
  56 + }
  57 + ?>
52 58 </div>
53 59 <div class="blog-post-date">
54 60 <span></span>
... ... @@ -56,10 +62,23 @@
56 62 </div>
57 63 </div>
58 64  
59   - <div class="new-portf-answer">
  65 + <div class="new-portf-answer artbox_comment_text">
60 66 <?= Html::encode($model->text) ?>
61 67 </div>
62   -
  68 + <div style="clear:both"></div>
  69 + <?php
  70 + /*
  71 + ?>
  72 + <div class="action_panel">
  73 + <ul>
  74 + <li style="display:inline-block" class="artbox_comment_reply">Ответить</li>
  75 + <li style="display:inline-block" class="artbox_comment_update">Редактировать</li>
  76 + <li style="display:inline-block" class="artbox_comment_delete">Удалить</li>
  77 + </ul>
  78 + </div>
  79 + <?php
  80 + */
  81 + ?>
63 82 </div>
64 83 <div class="style"></div>
65 84 </div>
66 85 \ No newline at end of file
... ...
console/migrations/m160304_081817_rating_table.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Migration;
  4 +
  5 +class m160304_081817_rating_table extends Migration
  6 +{
  7 + public function up()
  8 + {
  9 + $this->createTable('{{%rating}}', [
  10 + 'rating_id' => $this->primaryKey(),
  11 + 'date_add' => $this->timestamp()->notNull()->defaultExpression('NOW()'),
  12 + 'date_update' => $this->timestamp()->notNull()->defaultExpression('NOW()'),
  13 + 'user_id' => $this->integer(),
  14 + 'entity' => $this->string(),
  15 + 'value' => $this->integer(),
  16 + ]);
  17 +
  18 + $this->addForeignKey('rating_user', '{{%rating}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');
  19 + }
  20 +
  21 + public function down()
  22 + {
  23 + $this->dropForeignKey('rating_user', '{{%rating}}');
  24 + $this->dropTable('{{%rating}}');
  25 + }
  26 +
  27 +}
... ...
frontend/views/performer/portfolio-view.php
... ... @@ -2,13 +2,15 @@
2 2  
3 3 use common\models\Portfolio;
4 4 use common\models\User;
5   -use yii\helpers\Html;
6   -use yii\web\ViewAction;
  5 + use yii\helpers\Html;
  6 + use yii\web\ViewAction;
  7 + use yii\web\View;
7 8  
8 9 /**
9 10 * @var ViewAction $this
10 11 * @var User $user
11 12 * @var Portfolio $portfolio
  13 + * @var View $this
12 14 */
13 15 $this->params[ 'user' ] = $user;
14 16  
... ... @@ -16,7 +18,7 @@ use yii\web\ViewAction;
16 18 ?>
17 19 <div class="portfolio-new-page-wrapper style">
18 20 <div class="new-portfolio-bg style ">
19   - <?= Html::img($portfolio->minImg($portfolio->cover,'720', '280')) ?>
  21 + <?= Html::img($portfolio->minImg($portfolio->cover, '720', '280')) ?>
20 22 </div>
21 23 <div class="new-portfolio-icons-rating-wr style">
22 24 <div class="new-portfolio-icons">
... ... @@ -40,7 +42,7 @@ use yii\web\ViewAction;
40 42 <div class="portfolio-project-views-img">
41 43 <img src="/images/portfolio-project/ico-3.png"></div>
42 44 </div>
43   - <div class="portfolio-project-views-txt">XX</div>
  45 + <div class="portfolio-project-views-txt"></div>
44 46 </div>
45 47 </div>
46 48 </div>
... ... @@ -109,209 +111,213 @@ use yii\web\ViewAction;
109 111 }
110 112 ?>
111 113 </div>
112   -
113 114 <?php
114 115 echo \common\modules\comment\widgets\CommentWidget::widget([
115   - 'entity' => $portfolio::tableName().'-'.$portfolio->portfolio_id,
  116 + 'context' => $this,
  117 + 'entity' => $portfolio::tableName() . '-' . $portfolio->portfolio_id,
116 118 'comment_class' => \common\modules\comment\models\Comment::className(),
  119 + 'rating_class' => \common\modules\comment\models\Rating::className(),
117 120 'class_options' => [
118   - 'scenario' => is_int(\Yii::$app->user->getId())?\common\modules\comment\models\Comment::SCENARIO_USER:\common\modules\comment\models\Comment::SCENARIO_GUEST,
119   - 'user_id' => \Yii::$app->user->getId(),
  121 + 'scenario' => is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST,
  122 + 'user_id' => \Yii::$app->user->getId(),
  123 + 'guestComment' => true,
  124 + 'status' => \common\modules\comment\models\Comment::STATUS_ACTIVE,
120 125 ],
121   - 'list_options' => [
  126 + 'list_options' => [
122 127 'view' => 'list-comment',
123 128 ],
124   - 'form_options' => [
  129 + 'form_options' => [
125 130 'view' => 'form-comment',
126   - 'tag' => false,
  131 + 'tag' => 'div',
  132 + 'class' => 'artbox_comment_form',
127 133 ],
128   - 'options' => [
  134 + 'options' => [
129 135 'class' => 'new-portf-comments-wr style',
130 136 ],
131 137 ]);
132 138 ?>
133 139  
134 140 <?php
135   - /*
136   - ?>
137   - <div class="new-portf-comments-wr style">
138   - <div class="new-portf-comm-count">Комментарии: 3</div>
139   - <div class="new-portf-add-comm style">
  141 + /*
  142 + ?>
  143 + <div class="new-portf-comments-wr style">
  144 + <div class="new-portf-comm-count">Комментарии: 3</div>
  145 + <div class="new-portf-add-comm style">
140 146  
141   - <form action="">
142   - <div class="input-blocks-comm">
143   - <label for="input-txt-5">Имя</label>
144   - <input class="custom-input-4" id="input-txt-5" type="text">
145   - </div>
146   - <div class="input-blocks-comm">
  147 + <form action="">
  148 + <div class="input-blocks-comm">
  149 + <label for="input-txt-5">Имя</label>
  150 + <input class="custom-input-4" id="input-txt-5" type="text">
  151 + </div>
  152 + <div class="input-blocks-comm">
147 153  
148   - <label for="input-txt-6">e-mail</label>
149   - <input class="custom-input-4" id="input-txt-6" type="text">
150   - </div>
151   - <div class="input-blocks-comm area-comm">
152   - <label for="input-txt-7">Комментарий</label>
153   - <textarea class="custom-area-4" id="input-txt-7"></textarea>
154   - </div>
155   - <div class="input-blocks-comm-button style">
156   - <button type="submit" class="">Добавить комментраий</button>
157   - </div>
158   - </form>
  154 + <label for="input-txt-6">e-mail</label>
  155 + <input class="custom-input-4" id="input-txt-6" type="text">
  156 + </div>
  157 + <div class="input-blocks-comm area-comm">
  158 + <label for="input-txt-7">Комментарий</label>
  159 + <textarea class="custom-area-4" id="input-txt-7"></textarea>
  160 + </div>
  161 + <div class="input-blocks-comm-button style">
  162 + <button type="submit" class="">Добавить комментраий</button>
  163 + </div>
  164 + </form>
159 165  
160   - </div>
  166 + </div>
161 167  
162   - <div class="new-portf-comm-read-wr style">
163   - <div class="new-portf-comm-read">
164   - <div class="style">
165   - <div class="header-cabinet-foto">
166   - <img src="/images/ded-ico.png" alt="">
167   - </div>
168   - <div class="new-prof-wrapper-read">
169   - <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
170   - <div class="new-portf-comm-read-rating">
171   - <div class="rating">
172   - <!--оценка-->
173   - <input type="hidden" class="val" value="3"/>
174   - <!--количество голосов-->
175   - <input type="hidden" class="votes" value="12"/>
  168 + <div class="new-portf-comm-read-wr style">
  169 + <div class="new-portf-comm-read">
  170 + <div class="style">
  171 + <div class="header-cabinet-foto">
  172 + <img src="/images/ded-ico.png" alt="">
  173 + </div>
  174 + <div class="new-prof-wrapper-read">
  175 + <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
  176 + <div class="new-portf-comm-read-rating">
  177 + <div class="rating">
  178 + <!--оценка-->
  179 + <input type="hidden" class="val" value="3"/>
  180 + <!--количество голосов-->
  181 + <input type="hidden" class="votes" value="12"/>
  182 + </div>
  183 + </div>
  184 + <div class="blog-post-date">
  185 + <span></span>
  186 + <p>22.09.2015</p>
176 187 </div>
177 188 </div>
178   - <div class="blog-post-date">
179   - <span></span>
180   - <p>22.09.2015</p>
  189 +
  190 + <div class="new-portf-answer">
  191 + <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
  192 + <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
181 193 </div>
182   - </div>
183 194  
184   - <div class="new-portf-answer">
185   - <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
186   - <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
187 195 </div>
188   -
  196 + <div class="style"></div>
189 197 </div>
190   - <div class="style"></div>
191   - </div>
192 198  
193   - <div class="new-portf-comm-read">
194   - <div class="style">
195   - <div class="header-cabinet-foto">
196   - <img src="/images/ded-ico.png" alt="">
197   - </div>
198   - <div class="new-prof-wrapper-read">
199   - <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
200   - <div class="new-portf-comm-read-rating">
201   - <div class="rating">
202   - <!--оценка-->
203   - <input type="hidden" class="val" value="4"/>
204   - <!--количество голосов-->
205   - <input type="hidden" class="votes" value="12"/>
  199 + <div class="new-portf-comm-read">
  200 + <div class="style">
  201 + <div class="header-cabinet-foto">
  202 + <img src="/images/ded-ico.png" alt="">
  203 + </div>
  204 + <div class="new-prof-wrapper-read">
  205 + <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
  206 + <div class="new-portf-comm-read-rating">
  207 + <div class="rating">
  208 + <!--оценка-->
  209 + <input type="hidden" class="val" value="4"/>
  210 + <!--количество голосов-->
  211 + <input type="hidden" class="votes" value="12"/>
  212 + </div>
  213 + </div>
  214 + <div class="blog-post-date">
  215 + <span></span>
  216 + <p>22.09.2015</p>
206 217 </div>
207 218 </div>
208   - <div class="blog-post-date">
209   - <span></span>
210   - <p>22.09.2015</p>
  219 +
  220 + <div class="new-portf-answer">
  221 + <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
  222 + <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
211 223 </div>
212   - </div>
213 224  
214   - <div class="new-portf-answer">
215   - <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
216   - <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
217 225 </div>
218   -
  226 + <div class="style"></div>
219 227 </div>
220   - <div class="style"></div>
221   - </div>
222 228  
223   - <div class="new-portf-comm-read">
224   - <div class="style">
225   - <div class="header-cabinet-foto">
226   - <img src="/images/ded-ico.png" alt="">
227   - </div>
228   - <div class="new-prof-wrapper-read">
229   - <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
230   - <div class="new-portf-comm-read-rating">
231   - <div class="rating">
232   - <!--оценка-->
233   - <input type="hidden" class="val" value="5"/>
234   - <!--количество голосов-->
235   - <input type="hidden" class="votes" value="12"/>
  229 + <div class="new-portf-comm-read">
  230 + <div class="style">
  231 + <div class="header-cabinet-foto">
  232 + <img src="/images/ded-ico.png" alt="">
  233 + </div>
  234 + <div class="new-prof-wrapper-read">
  235 + <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
  236 + <div class="new-portf-comm-read-rating">
  237 + <div class="rating">
  238 + <!--оценка-->
  239 + <input type="hidden" class="val" value="5"/>
  240 + <!--количество голосов-->
  241 + <input type="hidden" class="votes" value="12"/>
  242 + </div>
  243 + </div>
  244 + <div class="blog-post-date">
  245 + <span></span>
  246 + <p>22.09.2015</p>
236 247 </div>
237 248 </div>
238   - <div class="blog-post-date">
239   - <span></span>
240   - <p>22.09.2015</p>
  249 +
  250 + <div class="new-portf-answer">
  251 + <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
  252 + <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
241 253 </div>
242   - </div>
243 254  
244   - <div class="new-portf-answer">
245   - <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
246   - <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
247 255 </div>
248   -
  256 + <div class="style"></div>
249 257 </div>
250   - <div class="style"></div>
251   - </div>
252 258  
253   - <div class="new-portf-comm-read">
254   - <div class="style">
255   - <div class="header-cabinet-foto">
256   - <img src="/images/ded-ico.png" alt="">
257   - </div>
258   - <div class="new-prof-wrapper-read">
259   - <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
260   - <div class="new-portf-comm-read-rating">
261   - <div class="rating">
262   - <!--оценка-->
263   - <input type="hidden" class="val" value="1"/>
264   - <!--количество голосов-->
265   - <input type="hidden" class="votes" value="12"/>
  259 + <div class="new-portf-comm-read">
  260 + <div class="style">
  261 + <div class="header-cabinet-foto">
  262 + <img src="/images/ded-ico.png" alt="">
  263 + </div>
  264 + <div class="new-prof-wrapper-read">
  265 + <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
  266 + <div class="new-portf-comm-read-rating">
  267 + <div class="rating">
  268 + <!--оценка-->
  269 + <input type="hidden" class="val" value="1"/>
  270 + <!--количество голосов-->
  271 + <input type="hidden" class="votes" value="12"/>
  272 + </div>
  273 + </div>
  274 + <div class="blog-post-date">
  275 + <span></span>
  276 + <p>22.09.2015</p>
266 277 </div>
267 278 </div>
268   - <div class="blog-post-date">
269   - <span></span>
270   - <p>22.09.2015</p>
  279 +
  280 + <div class="new-portf-answer">
  281 + <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
  282 + <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
271 283 </div>
272   - </div>
273 284  
274   - <div class="new-portf-answer">
275   - <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
276   - <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
277 285 </div>
278   -
  286 + <div class="style"></div>
279 287 </div>
280   - <div class="style"></div>
281   - </div>
282   - <div class="new-portf-comm-read">
283   - <div class="style">
284   - <div class="header-cabinet-foto">
285   - <img src="/images/ded-ico.png" alt="">
286   - </div>
287   - <div class="new-prof-wrapper-read">
288   - <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
289   - <div class="new-portf-comm-read-rating">
290   - <div class="rating">
291   - <!--оценка-->
292   - <input type="hidden" class="val" value="2"/>
293   - <!--количество голосов-->
294   - <input type="hidden" class="votes" value="12"/>
  288 + <div class="new-portf-comm-read">
  289 + <div class="style">
  290 + <div class="header-cabinet-foto">
  291 + <img src="/images/ded-ico.png" alt="">
  292 + </div>
  293 + <div class="new-prof-wrapper-read">
  294 + <div class="new-portf-comm-read-title"><a href="#">Петер Цумтор</a></div>
  295 + <div class="new-portf-comm-read-rating">
  296 + <div class="rating">
  297 + <!--оценка-->
  298 + <input type="hidden" class="val" value="2"/>
  299 + <!--количество голосов-->
  300 + <input type="hidden" class="votes" value="12"/>
  301 + </div>
  302 + </div>
  303 + <div class="blog-post-date">
  304 + <span></span>
  305 + <p>22.09.2015</p>
295 306 </div>
296 307 </div>
297   - <div class="blog-post-date">
298   - <span></span>
299   - <p>22.09.2015</p>
  308 +
  309 + <div class="new-portf-answer">
  310 + <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
  311 + <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
300 312 </div>
301   - </div>
302 313  
303   - <div class="new-portf-answer">
304   - <p>Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
305   - <p>Евровагонка — удобная в монтаже фасонная доска, которая позволяет создать обшивку из плотно пригнанных элементов с качественно обработанной поверхностью. Толщина евровагонки составляет 125 мм, общая ширина (с гребнем) 960 мм, рабочая ширина 880 мм.Балкон, обшитый вагонкой, выглядит аккуратно, стильно и уютно. Монтаж обшивки вполне возможно выполнить своими силами — достаточно иметь в распоряжении необходимые инструменты и владеть базовыми навыками строительно-ремонтных работ.</p>
306 314 </div>
307   -
  315 + <div class="style"></div>
308 316 </div>
309   - <div class="style"></div>
310   - </div>
311 317  
  318 + </div>
312 319 </div>
313   - </div>
314   - */
  320 + */
315 321 ?>
316 322 </div>
317 323 <script>
... ...
frontend/web/css/art_box.css
... ... @@ -4,4 +4,4 @@
4 4 }
5 5 .form_for_company .company_info {
6 6 display: none;
7   -}
8 7 \ No newline at end of file
  8 +}
... ...