Как прикрепить изображение к комментарию

Как реализовать такие комменты:
fishspace.ru/places/to/venevskij/platnik-vorotnya/
Николаевич
02 января 2015, 18:20
modx.pro
10
3 828
+1

Комментарии: 26

Наумов Алексей
03 января 2015, 10:08
1
0
Я делал так:

1. Немного модернизируем js файл от тикетс (точнее делаем копию оригинального и указываем путь к нему в настройках), мой файл
fishspace.ru/assets/components/tickets/js/web/fish_default.js
мои изменения отмечены комментариями // FishSpace
2. в форму добавления комментария добавляем код ниже textarea
<div>
  	  <p>
  	    <a id="commentImagesUpload" href="#"><i class="icon-camera"></i>Прикрепить изображение</a>
  	  </p>
  	  <div id="commentImagesPanel"></div>
  	</div>
В момент написания комментария прикрепленные фотки вставляются внутрь commentImagesPanel (и соответственно у пользователя есть предпросмотр их), а в момент нажатия кнопки «написать комментарий» — html код с комментарями добавляется в textarea (это делает скрипт из п.1) и все отправляется на сервер.

3. На ссылку commentImagesUpload нужно повесить ajax загрузчик файлов, у меня так:
$('#commentImagesUpload').click(function(){
    ImageUpload(true);
    return false;
  });
функция ImageUpload у меня довольно навороченная и приводить ее код не буду. Суть ее в том, что бы показать всплывающее окно, которое позволит выбрать файл и загрузить его на сервер. На сервере скрипт загружает картинку, делает для нее превью, и возвращает ответ в json:

$html_code = '<a href="myimage.jpg"><img src="mythumb.jpg" />';
$result = array('success' => true, 'html' => $html_code);
return htmlspecialchars(json_encode($result), ENT_NOQUOTES);
В общем такой костыль у меня прикручен.
    Максим Кузнецов
    05 января 2015, 09:00
    0
    Если есть возможность, было бы очень интересно посмотреть на Вашу функцию ImageUpload.

    У самого реализована связка загрузки изображений с ms2gallery-загрузчиком посредством очень топорного костыля, поэтому вопрос крайне актуален..)
      Наумов Алексей
      05 января 2015, 10:27
      0
      У меня жуткий костыль, код разбросан в 10 местах, суть такая:
      1. В низу страницы есть код скрытой формы, эта форма отображается при помощи fancybox при загрузке картинки.
      2. В форме есть input type=file, загрузка файлов идет по одному
      3. Сама форма отправляется на сервер через ajax (jquery forms)
      4. На севере висит php скрипт файл сохраняет и выдает в ответ сформированный html код со ссылкой на картинку и маленьким превью.
    Николаевич
    03 января 2015, 19:01
    0
    Спасибо! А как правильно прописать разрешение Jevix добавлять тег
    <div class="comm-img">
      Максим Кузнецов
      05 января 2015, 09:05
      +1
      Наборы параметров -> Comments -> Jevix

      cfgAllowTagParams
      {..., "div":{"class":["comm-img"]},...}

      cfgAllowTags
      Дописать тег div

      — только, насколько я понимаю, в данном способе тег выводится не в теле комментария (где текст), а в общем шаблоне комментария под ним с подцеплением результатов на лету.
      Николай Загумённов
      28 мая 2016, 23:40
      4
      +3
      Выяснил, что можно использовать для этих целей UserFiles.
      Надо только добавить плагин, который буде срабатывать после сохранения комментария (событие — OnCommentSave). Вообще очень много открыл для себя с этими плагинами =) В таблице компонента меняю поле parent на id созданного комментария.
      <?php
      // TicketCommentSave
      switch ($modx->event->name) {
          case 'OnCommentSave':
              // $modx->log(1, print_r(array_keys($scriptProperties), 1));
              if ($mode == 'new') {
              	// >> Подключаем UserFiles
      			$corePath = $modx->getOption('userfiles_core_path', null, $modx->getOption('core_path', null, MODX_CORE_PATH) . 'components/userfiles/');
      			$UserFiles = $modx->getService('UserFiles', 'UserFiles', $corePath . 'model/userfiles/', array('core_path' => $corePath));
      			// << Подключаем UserFiles
      			
      			$user_id = $modx->user->id; // id Авторизованного пользователя
      			
      			$files = $modx->getCollection('UserFile', array('parent' => $user_id));
      			foreach ($files as $file) {
      				$file->set('parent', $id);
      				$file->save();
      				if ($children = $file->getMany('Children')) {
      					foreach ($children as $child) {
      						$child->remove();
      					}
      					$file->generateThumbnails();
      				}
      			}
              }
          break;
      }
      В чанке формы добавления комментария надо добавить сам сниппет ufForm:
      [[!ufForm?
      	&class=`modUser`
      	&list=`comment`
      	&dropzone=`{"maxFilesize":2,"maxFiles":5,"acceptedFiles":".jpg, .jpeg, .gif, .png","template":"edit"}`
      ]]
      В чанке одного комментария(tpl.Tickets.comment.one.auth) добавить:
      Должна быть включена поддержка fenom в настройках pdotools.
      {$_modx->runSnippet('!pdoResources', [
      	'limit' 			=> 10,
      	'showLog'			=> 1,
      	'class' 			=> 'UserFile',
      	'loadModels' 		=> 'UserFiles',
      	'sortby' 			=> '{"rank":"ASC"}',
      	'tpl' 				=> '@INLINE <div class="item pull-left>
      						        <a href="{$url}" rel="fancybox"><img src="{$thumb}" alt=""></a>
      						    </div>',
      	'where' 			=> '{
      						        "UserFile.parent": ' ~ $id ~ ',
      						        "UserFile.createdby": '~ $createdby ~'
      						        
      						    }',
      	'leftJoin' 			=> '{
      								"Thumb": {
      									"class": "UserFile",
      									"on": "Thumb.parent = UserFile.id AND Thumb.properties LIKE \'%w\":120,\"h\":90%\'"
      								}
      						    }',
      	'select' 			=> '{
      								"UserFile": "url",
      								"Thumb": "Thumb.url as thumb"
      						    }',
      ])}
      Будет работать только для авторизованных пользователей, так как их id мы заполняем в parent таблицы компонента UserFiles.
        Павел Гвоздь
        29 мая 2016, 23:55
        +1
        У тебя в плагине ошибка.
        Ты получаешь все файлы юзера по его user_id, соответствующему свойству parent:
        $files = $modx->getCollection('UserFile', array('parent' => $user_id));
        Потом, ты у каждого файла перезаписываешь его parent, то бишь user_id, на id нового комментария:
        $file->set('parent', $id);
        Почему это плохо? Потому что юзер, чей id совпадает с id нового комментария, который ты напишешь, будет иметь доступ к тем фоткам, которые были добавлены в этот комментарий тобой. А ты доступа к этим фоткам уже не имеешь, по сути, ибо parent (читай user_id) файлов, которые были тобой загружены, уже не соответствует твоему user_id.
          Павел Гвоздь
          30 мая 2016, 00:49
          3
          +1
          Итого вот:

          В tpl.Tickets.comment.form вызываем форму загрузки файла:
          {$_modx->runSnippet('!ufForm', [
              'class' => 'modUser',
              'list' => 'comment-' ~ $thread,
              'tplForm' => 'uf.form',
              'dropzone' => '{
                  "maxFilesize": 2,
                  "maxFiles": 5,
                  "acceptedFiles": ".jpg, .jpeg, .gif, .png",
                  "template": "edit"
              }',
          ])}

          Важный момент, который ты почему-то не упомянул:
          Чанк uf.form переписываем так, чтобы там не было тега form (заменяем его на div):
          <div class="userfiles-form-wrapper">
              <div class="userfiles-form userfiles-dropzone" id="[[+propkey]]" data-clickable=".userfiles-form-clickable-[[+propkey]]" data-sorting="1">
                  <div class="dz-message needsclick">[[%userfiles_msg_needsclick]]</div>
              </div>
              <a class="userfiles-form-clickable userfiles-form-clickable-[[+propkey]]">[[%userfiles_msg_select_files]]</a>
          </div>
          Не знаю, насколько это правильно, но работает. :)

          В tpl.Tickets.comment.one.auth и tpl.Tickets.comment.one.guest прописываем вывод файлов комментария:
          {$_modx->runSnippet('!pdoResources', [
              'class' => 'UserFile',
              'loadModels' => 'UserFiles',
              'limit' => 10,
              'tpl' => '@INLINE
                  <div class="item pull-left">
                      <a href="{$url}" rel="fancybox"><img src="{$thumb}" alt=""></a>
                  </div>
              ',
              'leftJoin' => '{
                  "Thumb": {
                      "class": "UserFile",
                      "on": "Thumb.parent = UserFile.id AND Thumb.properties LIKE \'%w\":120,\"h\":90%\'"
                  }
              }',
              'select' => '{
                  "UserFile": "url",
                  "Thumb": "Thumb.url as thumb"
              }',
              'where' => '{
                  "UserFile.class": "modUser",
                  "UserFile.list": "comment-' ~ $id ~ '"
                  
              }',
              'sortby' => '{"rank":"ASC"}',
          ])}

          И плагин будет выглядеть так:
          switch ($modx->event->name) {
              case 'OnCommentSave':
                  if ($mode == 'new' && $modx->user->isAuthenticated($modx->context->key)) {
                      $corePath = MODX_CORE_PATH.'components/userfiles/';
                      if ($uf = $modx->getService('UserFiles', 'UserFiles', $corePath.'model/userfiles/', array('core_path' => $corePath))) {
                          if ($files = $modx->getCollection('UserFile', array('parent' => $modx->user->id, 'list' => 'comment-'.$object->Thread->name))) {
                              foreach ($files as $file) {
                                  $file->set('list', 'comment-'.$object->id);
                                  $file->save();
                                  
                                  if ($children = $file->getMany('Children')) {
                                      foreach ($children as $child) {
                                          $child->remove();
                                      }
                                      $file->generateThumbnails();
                                  }
                              }
                          }
                      }
                  }
                  break;
          }

          Костыльно, признаю… но другого ничего в голову не пришло. Помоему, просто с текущей версией UserFiles никак по другому не реализовать прикрепление изображений к комментариям.

          — Обновлено --

          Данная реализация разбивает файлы по группам comment-[[+id]], что позволяет более проще получить к ним доступ в бекенде на странице UserFiles или на вкладке UserFiles страницы редактирования юзера.
            Николай Загумённов
            30 мая 2016, 10:18
            0
            Большое спасибо за такой развернутый комментарий. Я почему-то всё время хотел использовать поле parent для привязки файлов к комменту. Думал про поле list, но смущало что этих листов будет потом очень много, но сейчас понимаю, что это не так критично нежели если id пользователя совпадет с id комментария.
            Про замену тэга form на div действительно забыл упомянуть, важный момент без которого работать не будет.
              Максим Кузнецов
              03 июня 2016, 18:42
              +1
              Интересное решение) А что насчет нагрузки?

              UPD: Возможно, лучше джоинить изображения, чем вызывать в каждом комментарии pdoResources или расширить таблицу комментариев, чтобы в ней хранилась информация о том, есть ли у комментария прикрепленные файлы.
                Павел Гвоздь
                04 июня 2016, 20:48
                0
                Возможно, лучше джоинить изображения, чем вызывать в каждом комментарии pdoResources
                Покажи, пожалуйста, пример, как ты заджоинишь к комментарию 10-50 файлов (в зависимости от кол-ва загруженных юзером) + превьюшки, если файл является изображением?
                  Test
                  04 июня 2016, 21:15
                  0
                  del
                    Максим Кузнецов
                    04 июня 2016, 21:19
                    +2
                    При помощи GROUP_CONCAT(), например.
                    (это не говоря о том, что я предложил вариант и без джоинов, но с доп. проверкой для избежания лишних запросов)
                      Павел Гвоздь
                      04 июня 2016, 23:13
                      0
                      Спасибо за GROUP_CONCAT, разобрался.
                      А зачем тебе второй аккаунт тут?)
                        Максим Кузнецов
                        04 июня 2016, 23:55
                        0
                        Только зарегистрировал чтобы проверить авторизацию — были проблемы со входом на основной аккаунт.

                        Не за что.)
                      Николай Загумённов
                      06 июня 2016, 14:14
                      2
                      +1
                      Попробывал сделать так:
                      {$_modx->runSnippet('!TicketComments', [
                          'showLog' => 1,
                      	'class' => 'TicketComment',
                          	'loadModels' => 'UserFiles',
                          	'leftJoin' => '{
                              "Thumbs": {
                                  	"class": "UserFile",
                                  	"on": "Thumbs.list = TicketComment.id AND Thumbs.properties LIKE \'%w\":120,\"h\":90%\'"
                              	}
                          	}',
                          	'select' => '{
                              	"TicketComment": "*",
                      	        "Thumbs": "GROUP_CONCAT(Thumbs.url) as thumbs"
                          	}',
                          	'groupby' => 'TicketComment.id',
                      ])}
                      В плейсхолдере thumbs получаю строку с картикками через запятую. Теперь осталось только сделать сниппет который будет обрабатывать эту строку.
                      Когда оставляю коментарий картинки не подгружаются сразу, надо обновить страницу, чтобы пути появились под комментом.
                      Как можно сделать чтобы они подгружались сразу?
                      P.S. Спасибо за GROUP_CONCAT()
                        Максим Кузнецов
                        06 июня 2016, 14:40
                        2
                        +2
                        Скорее всего, придется расширять функцию saveComment в
                        core/components/tickets/model/tickets/tickets.class.php

                        Если использовать феном, то можно обойтись и без сниппета:
                        {foreach $thumbs | split as $thumb}
                        	<!--Получаем основное изображение из превью 120х120, к примеру -->
                        	
                        	<a href='{$thumb | replace : ".w120.h120" : ""}'>
                        		<img src='{$thumb}' width='120' height='120' />
                        	</a>
                        {/foreach}
                Николаевич
                03 марта 2017, 09:52
                0
                А если пользователь после публикации комментария решит заменить изображение в отведенное для редактирования время? Ведь list не перезапишется из-за
                $mode == 'new'
                  Александр
                  15 июня 2017, 04:04
                  0
                  Сделали прикрепление файлов к комментариям по этой инструкции через UserFiles. Есть только одна проблема. Когда комментарий отправлен в форме загрузки файла прикрепленный к комментарию файл остается. Как сделать чтобы при отправке комментария форма UserFiles очищалась?
                    Александр
                    15 июня 2017, 04:29
                    0
                    Сделал так в файле assets/components/tickets/js/web/_default.js на сохранение комментария добавил
                    $('.dz-preview').remove();
                    $('.dz-message').show();
                    Andrey
                    20 августа 2018, 03:18
                    0
                    Приветствую! Понимаю что уже прошло много времени и воды утекло, но нашел это решение и применил его. Все круто (почти), комменты при первом сохранении разбивает как надо! НО!
                    После редактирования уже начинают появляться проблемы…
                    При редактировании прикрепленные фотографии не отображаются, почему?
                    потому что при этой записи:
                    'list' => 'comment-' ~ $thread,
                    Форма Добавления комментария и Форма редактирования комментария ведут себя по разному…
                    Форма комментария получается записывает (соответственно и сниппет отрабатывает) все это дело как:
                    comment-[[+id]]
                    А форма редактирования, вот так:
                    comment-resource-[[+здесь ID ресурса есена, т.к. написано $thread]]
                    И получается чехарда, сохраняю (формой редактирования), получается, что в базу (а именно в поле LIST) улетает:
                    comment-resource-[[+здесь ID ресурса есена, т.к. написано $thread]]
                    И при этом комментарии начинают глючить и тупить, а так же файл остается висеть, т.к. теперь у него назначно в LIST:
                    comment-resource-[[+здесь ID ресурса есена, т.к. написано $thread]]
                    Если есесна я назначу ему принудительно, например так:
                    'list' => 'comment-10'
                    То есесна как только я захочу отредактировать этот комментарий, то все чики пуки, файлы отображаются, перезагружаются, удаляются или загружаются новые именно к этому комменту!

                    Помогите пожалуйста понять, сделал все как описано именно в этой теме! Заранее огромное спасибо!
                  Михаил
                  29 июня 2016, 22:17
                  0
                  А как разрешить авторизованным пользователям вставлять картинки в комментарии???
                  А то у меня пишет доступ запрещён.
                    Михаил
                    29 июня 2016, 22:20
                    0
                    Ой сори разобрался))) нужно просто в Доступах к контекстам добавить
                    web
                    Member — 9999
                    UserFilesPolicy
                      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                      26