[EVO] Selector - custom TV для составления списка документов

Замена mm_ddSelectDocuments специально для webber

В отличие от mm_ddSelectDocuments:
  • уживается с SimpleGallery;
  • благодаря DocLister позволяет выбирать данные для списка как угодно и откуда угодно;
  • список результатов поиска можно оформлять по-всякому (реализовано с помощью prepare в DocLister);
  • код полностью открыт (была мысль разобраться в конфликте mm_ddSelectDocuments с SimpleGallery, но минифицированный js сразу же отбил желание).
В недостатки зачислю то, что у меня нет возможности сделать такую классную документацию как у Divan.Design. Но код получился простой, разобраться при желании не сложно.

Скачивать здесь: github.com/Pathologic/Selector
Для работы требуется DocLister.

Больше и нечего написать про этот компонент, разве что некоторых пояснений требует процесс настройки под себя. Сразу поясню на примере.

Допустим, есть tv-параметр c названием related, для хранения списка похожих товаров. Чтобы его поведение отличалось от базового, нужно создать в файле assets/tvs/selector/lib/related.controller.class.php класс:

<?php namespace Selector;
include_once(MODX_BASE_PATH.'assets/tvs/selector/lib/controller.class.php');
class RelatedController extends SelectorController {
... //переопределяем что нужно
}


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

<?php namespace Selector;
include_once(MODX_BASE_PATH.'assets/tvs/selector/lib/controller.class.php');
class RelatedController extends SelectorController {
    public function __construct($modx) {
        parent::__construct($modx);
        $this->dlParams['parents'] = 5;
        $this->dlParams['addWhereList'] = 'c.published = 1';
    }
}


Если эта часть не понятна, то могу посоветовать обратиться сюда: bezumkin.ru/training/course3/

Следует обратить внимание, что параметр — related, название файла — related.controller.class.php, а название класса — RelatedController (с большой буквы).

Можно также подгружать нужный класс вручную с помощью плагина на OnManagerPageInit. В этом случае значение имеет только правильное название класса. Также есть ограничение на название tv-параметра: допускаются только латинские буквы и символ подчеркивания.

81 комментарий

avatar
отличная получилась вещь :)
avatar
Заменив тут
[+pagetitle+]
на
[[Breadcrumbs? &hereId=`[+id+]` &showHomeCrumb=`0`]]
и убрав у этих элементов float:left тут получил как раз то, что хотел — построчный вывод и с полными путями — теперь о mm_ddSelectDocuments, который грузит сразу все документы из дерева на страницу можно забыть навсегда :)
avatar
Надо изменить еще prepare в контроллере тут, чтобы в таком же виде новые записи добавлялись.
Ну и можно без хаков все это делать, хотя для конкретного проекта может быстрее будет и хак (:
avatar
Да, там я заменил
$data['text'] = "{$data['id']}. {$data['pagetitle']}";

на
$data['text'] = "{$data['id']}. {$data['pagetitle']}" . "<div><small>{$docCrumbs}</small></div>";


заодно видна разница между «старыми» и «вновь добавляемыми» записями из-за разных форматов — главное еще тут не забыть height на min-height заменить, чтобы высота не обрезалась:))
avatar
Я еще подумываю сделать такой же TV для работы с тэгами и TagSaver, тем более, что скрипт Tokenize для этого хорошо подходит, да и автор его поддерживает в отличие от аналогичных скриптов, которые я нашел.
avatar
Ну я его как раз с tagsaver и использовал — вроде они друг другу хорошо подходят.
Правда пришлось немного пару строк допилить сам tagsaver, чтоб там можно было задавать не 1 тв, а сразу несколько (через запятую — &tv=ID TV-параметров), и даже больше — сразу несколько категорий тв через запятую (&tv_cats=ID категорий TV-параметров) — gist.github.com/webber12/6aee0f0239f2bfc48de5
avatar
TagSaver делался из расчета 1 ТВ = 1 плагин. Ибо: разделители могут быть разные у разных ТВ параметров. Да и черт ногу сломит когда за сохранение нескольких ТВ параметров отвечает сразу один плагин. Ну в общем это моя философия. Нравится оперировать группами — пожалуйста. Просто мне за такое «удобство» в долгосрочной перспективе приходилось расплачиваться частичной переделкой проекта.
avatar
Ну тут кому как удобнее — тем более доработок там 5 строк. В принципе — разделителя стандартных всего 2 — или запятая (как в случае с тегами, mm_ddSelectDocuments, picDocsInTree + текущим решением) или двойной вертикальный слэш || (в случае со стандартными ТВ с множественным выбором — checkbox, multiselect и т.п.). Мне показалось, что 2 плагина (один на запятую, второй на ||), в каждом из которых перечислены через запятую нужные ТВ — лично для меня удобнее :)
Ну а возможность задания категорий я делал также для удобства — у меня есть категория «Параметры для фильтрации» — чтобы не приходилось после добавления очередного параметра вносить изменения в плагин или копировать еще один — сразу задал id данной категории и «спи спокойно» — сколько бы туда не добавилось ТВ в эту категорию — они автоматом начнут разноситься в таблицы tagSaver-а.
avatar
Спасибо за плагин. Если можно вопрос: куда смотреть чтобы изменить хранящиеся в тв значения с ID на pagetitle?
avatar
Можно хакнуть файл selector.tpl (: Заменить valueField: 'id' на valueField: 'pagetitle'. Если без хака:
1. Делаете копию tpl/selector.tpl (пусть будет _selector.tpl), меняете что нужно.
2. Создаете файл lib/myselector.class.php:

<?php namespace Selector;
inlcude_once(include_once(MODX_BASE_PATH.'assets/tvs/selector/lib/_selector.class.php');
class MySelector extends Selector {
    public $tpl = 'assets/tvs/selector/tpl/_selector.tpl';
}
?>

3. Создаете файл myselector.customtv.php:
<?php
include_once(MODX_BASE_PATH.'assets/tvs/selector/lib/myselector.class.php');
$selector = new \Selector\MySelector (
    $modx,
    $row
);

echo $selector->render();

4. Создаете TV типа Custom Input, в возможные значения пишите:

@INCLUDE/assets/tvs/selector/myselector.customtv.php

Таким образом сможете использовать и оригинальный вариант, где хранятся id, и ваш, где хранятся pagetitle.
avatar
Я изначально так сделал, проверил и сейчас. Проблема в том, что данные сохраняются, но потом не отображаются в поле joxi.ru/GrqMXxLtDMdWrz
avatar
Переопределить нужно еще

public function getTplPlaceholders() {
   $ph = array (
       'tv_id'      => $this->tv['id'],
       'tv_value'   => $this->tv['value'],
       'tv_name'    => $this->tv['name'],
       'site_url'      => $this->modx->config['site_url'],
       'values'        => !empty($this->tv['value']) ? $this->modx->runSnippet('DocLister',array(
       'idType'    => 'documents',
       'documents' => $this->tv['value'],
       'showNoPublish'=> 1,
       'sortType'  => 'doclist',
       'tpl'       => '@CODE: <option value="[+id+]" selected>[+id+]. [+pagetitle+]</option>')) : ''
   );
        return $ph;
    }

Вместо вызова DocLister поставить вызов сниппета или еще метод в класс добавить, который по аналогии выведет значения.
avatar
повозился конечно, но сделал, спасибо. Правда чертовски не хотелось разбираться и сделал грязно и с хаками, но зато работает joxi.ru/DmBXLqNslDn6AP )) и используя разделитель в || можно рулить в eFiltr
что-то подобное надо замутить в ядре, поскольку классический мультиселект не позволяет выбирать последовательность пунктов.
avatar
Вы не использовали Selector на новой modx? Мне никак не удается заставить работать.

Сделал все по инструкции — и все равно никак.
avatar
Обновляю регулярно, проблем не испытывал. Всё прекрасно пашет.
avatar
Буду разбираться дальше.
avatar
Ну и я подумал, что в случае с pagetitle разделять значения запятой может оказаться не очень удобно, поэтому теперь можете и свой разделитель использовать.
avatar
Подскажите, как в наследуемом классе обертке подставить id редактируемого документа, чтобы исключить его из выборки?
Так не работает (это я наугад попробовал):
$this->dlParams['addWhereList'] = 'NOT c.id='. $modx->documentIdentifier;

так тоже
$modx->documentObject['id']

Как правильно делать?
Комментарий отредактирован 2016-12-20 12:15:39 пользователем nohc
  • nohc
  • 0
avatar
Если делать правильно, то никак, потому что в админке нет documentObject и documentIdentifier. А неправильно я сам сделаю скоро (:
avatar
Если чего-то еще не хватает, то самое время об этом написать, раз уж я затеял обновить компонент. Пока что будут добавлены конфиги и id документа.
avatar
не знаю как сейчас, но как-то использовал Ваше решение и тогда не хватало как раз показывать список по двойному клику или по клику. Пришлось дописывать/переписывать js под задачу.

Понятно, что такие задачи опциональны, но если будет возможность как-то в конфиге определять по какому принципу отображать список — будет удобно :)
avatar
Всё, сдаюсь )) не соображаю уже, помогайте, ребята ))
Скачал-распаковал Selector, создал ТВ selector, назначил его нужному шаблону, присвоил ему тип ввода selector. И не работает.

MODx новая. Консоль чистая, только ошибки CodeMirror там.

avatar
Сделал еще и так:
Создал ТВ blocks с типом ввода selector, создал файл blocks.controller.class.php в папке lib плагина с таким кодом (страницы для выбора у меня в папке с ИД 14):

<?php namespace Selector; 
include_once(MODX_BASE_PATH.'assets/tvs/selector/lib/controller.class.php'); 

class BlocksController extends SelectorController {
    public function __construct($modx) {
        parent::__construct($modx);
        $this->dlParams['parents'] = '14';
        $this->dlParams['addWhereList'] = 'c.hidemenu = 0';
    }
}


Не работает. Дело в новом JQuery, что в админке?
avatar
Добавили ли в папку assets/js папки tokenize и sortable?
avatar
У автора, кстати, уже версия 2.6, может попробовать обновить
avatar
Обновил tokenize — все то же самое. Скорее всего, какая-то глупая ошибка где-то затесалась, буду смотреть.
avatar
Да, tokenize добавляется при установке Selector, а sortable уже была там. Да и если бы не было, в консоли бы ошибка была, а в консоли пусто…
avatar
Привет, убери в окне <select id=«tokenizetv__»
display: none;

и заработает
avatar
Убирал это вчера в Инструментах разработчика (в браузере). но все равно не полностью работало. Сейчас в коде поищу, откуда оно берется.
avatar
У меня тож было пустое окно, как и у тебя на фото выше…
Поправил css-ку и начал вводить в окно id ресурсов… моментально все появилось…
Последняя Димина сборка + PHP 5.3.29
avatar
Ага… а у меня PHP 5.5 — сейчас быстренько проверю оба направления — CSS и версию ПХП сменю.
avatar


Нижная картинка тыкаю мышом-начинаю вводить находит совпадение — выдает… это с display: none;

Верхняя с отключенным…
avatar
У меня ничего не ищет и не выдает. Хоть с отключенным, хоть как. И ПХП менял.
avatar
upd. проверил и на 5.5 — работает… на Бегете хост

Поставил селект как в примере, и твой с ТВ blocks, тоже пашет…
Комментарий отредактирован 2017-02-21 14:22:51 пользователем f1fanatic
avatar
Я тоже. слава богу, разобрался. В Админке же кеш браузера даже после Ctrl+F5 сохраняется, я очистил через chrome/settings/cookies, CSS обновилась, и заработало.

Спасибо тебе за неравнодушие :)
Комментарий отредактирован 2017-02-21 14:32:23 пользователем Harand
avatar
deleted
Комментарий отредактирован 2017-02-21 13:58:04 пользователем Harand
avatar
Если можно, вкратце — как сделать:
1) показывать только ресурсы из той же папки, в которой и текущий,
2) а также отображать в выборе не pagetitle, а menuttile.

Я создал ТВ project_variants, файл project_variants.controller.class.php со следующим кодом:

<?php namespace Selector;

include_once(MODX_BASE_PATH.'assets/tvs/selector/lib/controller.class.php'); 

class Project_variantsController extends SelectorController {
    public function __construct($modx) {
        parent::__construct($modx);
        $this->dlParams['api'] = 'id,pagetitle,menutitle,parent,html,text';
        $this->dlParams['parents'] = $modx->documentIdentitfier;
        $this->dlParams['textField'] = 'menutitle';
    }
}

Но ищет по-прежнему среди всех ресурсов (как при родитель = 0), и выдает по-прежнему pagetitle.
avatar
$modx->documentIdentitfier
— работает только для фронта, для custom TV, особенно при ajax-запросе это точно не работает.
avatar
Неплохо бы вот тут допилить, чтобы в параметры поиска передавались не только данные о tv, но и о ресурсе, где этот TV вызывается — т.е. id (для существующего ресурса) либо pid для нового. Тогда эти параметры можно было бы использовать в собственном контроллере.

А насчет menutitle — опять же в собственном контроллере надо и вот это изменить :) Да и в целом заменить там $data['pagetitle'] на $data[$dlParams->textField] не помешало бы, иначе не очень понятно для чего эта настройка существует :)
Комментарий отредактирован 2017-04-19 09:52:18 пользователем webber
avatar
Эх, думал — быстренько сделаю… придется ковыряться.
P.S. Спасибо за ответ.
avatar
Надо подождать, что скажет автор — возможно где-то id запрашивающего документа уже имеется — вроде там в выпадающих вариантах текущий документ исключается, т.е. он определен :)
avatar
Автор молчит пока ))
avatar
Да, надо переделывать, забыл совсем про этот компонент (:
avatar
Буду рад, немного подзадонатить готов ))
avatar
Поправочка
$data[$dlParams->textField]
читать как
$data[$this->dlParams['textField']]
avatar
Вообще, ведь в controller.class.php используется конструкция $modx->documentObject, и я грешным делом подумал — а мой контроллер ведь расширение этого класса, значит и в нем можно.

В общем, надо повнимательней посмотреть.
avatar
Она там не используется, это просто хак для того, чтобы DLCrumbs к искомому ресурсу мог построить «крошки».

п.с. по крайней мере у меня такое сложилось впечатление, возможно, обманчивое :)
Комментарий отредактирован 2017-04-19 10:17:01 пользователем webber
avatar
Все верно. Вообще это Женя придумал, а я откуда-то скопировал.
avatar
Хитро, блин ))
avatar
Обновил. Теперь есть конфиги, параметры документа в запросе и список по двойному клику (:
avatar
Круто! потестю, если есть баги — напишу, и обязательно задоначу. И другим порекомендую задонатить.
Комментарий отредактирован 2017-04-24 06:55:51 пользователем Harand
avatar
Где-то тут были ваши реквизиты для доната, но искать долго. Киньте пожалуйста ссылочку или просто здесь напишите, куда донатить.
avatar
Яндекс 410011458897796
avatar
Еще одна очень ценная доработка — это выводить в начале списка «точное совпадение», а потом уже like — иначе у меня есть, например, название города «минск» и мне нужен именно он, а мне выдает 15 вариантов со словом «минский» и никак я до собственно «минска» добраться не могу :)
avatar
Идея хорошая, но думаю, что DocLister так не сможет. Разве что два запроса делать.
Комментарий отредактирован 2017-04-24 16:01:45 пользователем Pathologic
avatar
Надо что-то типа
SELECT pagetitle, IF(pagetitle='запрос', 1, 0) as tochno ... ORDER BY tochno ASC,pagetitle ASC
в DL как-то запихнуть :)
avatar
Или через prepareWrap попробовать словить весь массив и отсортировать по новой )
avatar
Может сделать так, что если вводится "=текст", то ищет WHERE `pagetitle`=«текст», а если просто «текст», то через like?
avatar
Ну как вариант — вполне нормально — если первый символ знак равно = — то ищет точное совпадение, если нет — по like.
avatar
Задонатил сумму, равную первым трем цифрам числа Пи ))
avatar
Спасибо.
avatar
Перенес на реальный сайт, создал свой ТВ variants и стандартный ТВ selector. Оба ТВ имеют тип ввода selector.

Для variants создал конфиг config/variants.php, где немного поменял шаблон — вписал menutitle вместо pagetitle.

'tokenTpl' => '@CODE: <option value="[+id+]" selected>[+id+]. [+menutitle+]</option>'


Но выводится по-прежнему pagetitle.

Кроме того, для variants создал файл variants.controller.class.php, в котором ради эксперимента задал опред. родителя,

$this->dlParams['parents'] = 62;


но ищется не в заданном родителе, а в папке, в которой находится редактируемый док-т.

Стандартный ТВ selector, как и положено, ищет по всему сайту, но и в нем, и в variants напрочь отсутствуют крошки.

Не посмотрите сайт? я еще донат подкину, надо ведь до ума довести.
avatar
Посмотрю.
avatar
Обязательно обратите внимание на этот коммент, похоже причина всех ошибок, включая отсутствие крошек и неработающие конфиги — в кешировании.

Как только я глянул на новом браузере — конфиги заработали. Например, я установил ненужную родительскую папку 62 (ради эксперимента), и (по двойному клику на пустом поле для ввода) стали «выпадать» все документы из этой папки.

Также появились крошки — в прошлом браузере их не было, так как был закешированный вызов сниппета Breadcrumbs, который, естетсвенно, ничего не выдавал в этой ситуации.

Но еще раз поменял в параметрах родит. папку на новую (в том же браузере) — ничего не произошло, по двойному клику выдается закешированный результат из «старой» папки.

А вот если набираешь «новый» запрос в поле, напр. ID — все выдается как надо, из нужной папки — запрос-то еще не закеширован.

Сегодня сил уже нет, я бегло прочел такое:
В случае, если необходимо отменить кэширование, необходимо добавлять к строке запроса случайное значение, или если для ajax запроса используются библиотеки типа JQuery, нужно добавить параметр cache: false, этот параметр включает возможность добавления случайного значения к строке запроса — автоматически.
P.S. Доступы вышлю в личку.
Комментарий отредактирован 2017-04-30 18:38:22 пользователем Harand
avatar
Потратил кучу времени — отключал opcache на сервере, чистил кеш сайта, чистил кеш и локальное хранилище в Хроме — ничего.

И совершенно выпустил из вида кеширование Ajax-запросов. Открыл админку в новом браузере — и (о чудо!) изменения появились!

Но стоило сделать парочку поисков, и даже при новом изменении, например, кастомного конфига ТВ-параметра, «старые» аякс-запросы отдают старые результаты. А новые запросы (которых ранее не было) — всё Ок.

Видимо, механизм кеширования аякс отличается от обычного, и не чистится чисткой кеша браузера.

Если я прав, стоит добавить в код отмену кеширования результатов аякс-запросов.
avatar
Для меня Гитхаб — это какой-то кошмар…

Отловил у вас пару багов в новом Selector, хотел сначала обновить свой форк Селектора — блин, как-то волшебно создался ненужный PR у вас. Я его перенес в Closed, не обращайте на него внимания.

Сейчас сделаю новый форк и запулю правки.
avatar
Всё, отправил ПРы.
avatar
Добавил возможность поиска по точному совпадению, параметры для построения начального списка вынес в конфиг (это дает возможность работать с любыми таблицами), решил проблему с кэшированием (:
avatar
Супер! Компонент приобретает светский лоск. Потестю, задоначу :)
avatar
Потестил, вроде еще одну небольшую шероховатость нашел. В личку отправил.
avatar
Исправил.
avatar
Не совсем :) issue отправил.
avatar
Я лично использую вот так

'tpl' => '@CODE: <option value="[+id+]" selected>[+id+]. [[Breadcrumbs? &hereId=`[+id+]` &showCurrentCrumb=`0` &showHomeCrumb=`0`]] / [+pagetitle+]</option>'
— так оно нагляднее получается в выпадающем списке. Хотя по идее не отказался бы и от встроенного подобного функционала на основе DLCrumbs — раз уж он все-равно необходим для отображения крошек :)
avatar
Что-то я не понял, какой встроенный функционал нужен.
avatar
Чтобы везде были крошки, в том числе и в приведенной выше строке — а не просто название документа. Документов с одинаковыми названиями в разных папках может быть несколько и только по их id вряд ли сильно удобно ориентироваться :) Т.е. чтобы вот в этой самописной строчке

'tpl' => '@CODE: <option value="[+id+]" selected>[+id+]. [[Breadcrumbs? &hereId=`[+id+]` &showCurrentCrumb=`0` &showHomeCrumb=`0`  &respectHidemenu=`0`]] / [+pagetitle+]</option>'
вместо Breadcrumbs был просто плейсхолдер [+path+] или [+breadcrumbs+] и в итоговом списке отображались не только документы, но и пути до них.
avatar
Понятно. Cейчас все параметры для вывода можно вписать в конфиг, в том числе и prepare для крошек.
avatar
Насколько я понял, prepare надо делать еще одним элементом массива $this->config['tokenConfig'] исходя из этого. Мне все-таки кажется, что этот «крошечный» prepare удобнее было бы запилить по умолчанию, в конфиге задавать только плейсхолдер [+crumbs+], а не копировать из конфига в конфиг одну и ту же prepare-функцию, которую, если потом надо будет подправить — придется править во множестве пользовательских конфигов. Или есть какой-то более прямой путь? :)
avatar
Можно этот prepare вынести в отдельный класс и подключать его в конфиге.
avatar
Продолжаю тестить компонент. Нашел такую особенность — не показывает документы с isfolder = 1, то есть папки не показывает.

Так и было задумано?
avatar
Нужно смотреть параметры DocLister.
avatar
(РЕШЕНО) Скажите, что Selector выводит в случае, если ничего не выбрано?
Почему-то DocLister &documents не работает в этом случае :(
( &parents задано в любом случае, + хотелось, чтобы ещё подмешивалось из &documents, если задано — всё ок, но если не задано — документы вообще не отображаются).
UPDATE Решено, по умолчанию TV выводился пробел
Комментарий отредактирован 2017-07-16 14:21:31 пользователем Jassie
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.