Modx фільтри. Фільтри, вони модифікатори, в CMF MODx Revolution. Створюємо нові параметри та присвоюємо значення

Головна / Корисне ПЗ

Фільтри в революції дозволяють керувати способом представлення даних. Вони дозволяють змінювати значення усередині шаблонів.

У революції вихідний фільтр застосовується один або більше разів із серії вихідних модифікаторів, які поводяться подібно до PHx викликів у MODx Evolution- За винятком, що вони вбудовані в ядро. Синтаксис виглядає так:

[ ]

Вони також можуть бути з'єднані (виконується зліва направо):

[ ]

Ви також можете використовувати їх, щоб змінити вихід сніпету; увага, модифікатор йде після імені сніпета і перед знаком питання, наприклад,

[ ]

У наступній таблиці наведено деякі з існуючих модифікаторів і наведено приклади їх використання. Хоча наведені нижче приклади для деяких тегів, вихідні модифікатори можуть бути використані з будь-яким тегом MODx. Переконайтеся, що модифікатор отримує дані.

Умовні модифікатори:

Модифікатор

Опис

приклад

if, input

Логічне АБО

[ [+numbooks:is=`5`:or:is=`6`:then=`There are 5 or 6 books!`:else=`Not sure how many books`] ]

Логічне І

isequalto, isequal, equalto, equals, is, eq

[ [+numbooks:isequalto=`5`:then=`There are 5 books!`:else=`Not sure how many books`] ]

notequalto, notequals, isnt, isnot, neq, ne

[ [+numbooks:notequalto=`5`:then=`Not sure how many books`:else=`There are 5 books!`] ]

greaterthanorequalto, equalorgreaterthen, ge, eg, isgte, gte

Більше або дорівнює

[ [+numbooks:gte=`5`:then=`There are 5 books or more than 5 books`:else=`There are less than 5 books`] ]

isgreaterthan, greaterthan, isgt, gt

[ [+numbooks:gt=`5`:then=`There are more than 5 books`:else=`There are less than 5 books`] ]

equaltoorlessthan, lessthanorequalto, el, le, islte, lte

Менше або дорівнює

[ [+numbooks:lte=`5`:then=`There are 5 or less than 5 books`:else=`There are more than 5 books`] ]

islowerthan, islessthan, lowerthan, lessthan, islt, lt

[ [+numbooks:lt=`5`:then=`There are less than 5 books`:else=`There are more than 5 books`] ]

[ [+numbooks:lt=`1`:hide] ]

[ [+numbooks:gt=`0`:show] ]

[ [+numbooks:gt=`0`:then=`Now available!`] ]

[ [+numbooks:gt=`0`:then=`Now available!`:else=`Sorry, currently sold out.`] ]

memberof, ismember, mo

[ [+modx.user.id:memberof=`Administrator`] ]

Строкові модифікатори:

Модифікатор

Опис

приклад

Якщо не порожньо

[ [+numbooks:cat=`books`] ]

lcase, lowercase, strtolower

Транформація у малі літери

[ [+title:lcase] ]

ucase, uppercase, strtoupper

Трансформація у великі літери

[ [+headline:ucase] ]

Перша буква слова заголовна

[ [+title:ucwords] ]

Перша буква заголовна

[ [+name:ucfirst] ]

htmlent, htmlentities

Заміна тегів HTML

[ [+email:htmlent] ]

esc,escape

Безпечно прибирає символи

[ [+email:escape] ]

Заміна перекладу каретки, табуляції та безлічі прогалин на одну прогалину

[ [+textdocument:strip] ]

stripString

Видаляє значення з рядка

[ [+name:stripString=`Mr.`] ]

Заміна значення

[ [+pagetitle:replace=`Mr.==Mrs.`] ]

striptags, stripTags, notags, strip_tags

Прибирає HTML теги

[[+code:strip_tags=`

len,length, strlen

Довжина рядка

[ [+longstring:strlen] ]

reverse, strrev

Реверс рядка

[ [+mirrortext:reverse] ]

Wordwrap

Новий рядок після вказаної кількості символів

[ [+bodytext:wordwrap=`80`] ]

wordwrapcut

Вставляє новий рядок після певної кількості символів.

[ [+bodytext:wordwrapcut=`80`] ]

Кількість символів, що виводиться

[ [+description:limit=`50`] ]

ellipsis

Обрізання рядка після вказаної кількості символів

[ [+description:ellipsis=`50`] ]

Відображає сирий елемент без тега. Корисно для документації.

[ [+showThis:tag] ]

Якщо значення може змінюватися динамічно, його слід зробити некешованим. Наприклад:

[ [+placeholder:default=`A default value!`] ]

Це означає, що значення іноді може бути порожнім, а іноді ні. Навіщо його зберігати у кеші? Це може виключити, що значення може з'явитися.

Якщо ви не впевнені, чи буде результат при виконанні сніпета, то логічно зробити значення за замовчуванням:

[ [!getResources:default=`Sorry - не збирається вашого search.`? &tplFirst=`blogTpl` &parents=`2,3,4,8` &tvFilters=`blog_tags==%%` &includeTVs=`1`] ]

Сьогодні корисна стаття про фільтри phx та їх модифікатори MODX Revo за допомогою яких ви зможете прямо всередині шаблонів, маніпулювати значенням різних тегів.

Навіщо вони потрібні?

phx модифікаториполегшують життя modx розробникам. Допустимо у нас є сайт з каруселлю зображень (ну або з банером), який потрібно виводити тільки на головній сторінці . Для цього достатньо помістити його в окремий чанк і вивести в шаблоні за допомогою такої конструкції

Де: 1 - id головної сторінки,
$carusel- Чанк з кодом каруселі (банера).
Тільки повні чайники створюють новий шаблонза кілька рядків коду каруселі. Я теж таким був, загалом не впадаємо у відчай і впроваджуємо phx в розробку.

Розберемо вищенаведену конструкцію докладніше:

[[*id:is=`1`:then=`[[$carusel]]`]]

*id- Виводить id поточної сторінки;

:is=`1`:then=

— перевіряє чи *id == 1? і якщо одно, то виводиться вміст then;
$carusel- Виводить чанк carusel.

Замість *id, можна використовувати й інші поля, наприклад *template - виведе поточний шаблон. Або можна перевіряти заповнене чи ні TV-поле (нехай буде *keywords) і якщо воно заповнене, то виводити його. Розберемо даний випадокдетальніше. Дано стандартну розмітку:

Завдання:не виводити цей рядок, якщо TV keywords не заповнено.
Рішення.

[[*keywords:!empty=` `]]

Навантаження

Потрібно стежити за обробкою модифікаторів, бездумне їхнє використання викличе зайві навантаження. Повернемося до каруселі, цей записзчитується зліва направо і МОДХ виконує всі вкладені умови, незалежно від того, вірна умова чи ні, чи виводиться на поточній сторінці вміст [[$carusel]], у будь-якому випадку його вміст обробиться. У зв'язку з цим доцільніше переписати запис:

[[$caru[[*id:is=`1`:then=`sel`]]]]

У цьому випадку вміст чанка $carusel, буде оброблено у разі, якщо виконується умова

*id:is=`1`

т.к. виконується

[[*id:is=`1`:then=`sel`]]

і якщо id поточної сторінки дорівнює 1, останнє обробляється [[$carusel]]якщо id не дорівнює 1, тоді - [[$caru]]. А якщо чанка $caru- немає в елементах, то й навантаження не буде.

А взагалі ідеальний висновок виглядатиме так.

[[$[[*id:is=`1`:then=`carusel`]]]]

Про те, як правильно інтегрувати верстку в modx revoрекомендую почитати тут.

Примітка! Ви можете комбінувати скільки завгодно модифікаторів під логіку роботи компонентів сайту, але головне пам'ятайте їх основна суть. полегшити розробку, а чи не ускладнювати без того складні завдання. Зазвичай, найефективніший і дієвий спосіб— це найпростіший, оскільки чим простіше і зрозуміліша конструкція — тим легше з нею працюватиме надалі. Нижче наведено основні модифікатори, які можна використовувати для будь-якого тега МОДХ Рево.

Ланцюжки модифікаторів

Хорошим прикладом побудови ланцюжка буде форматувати рядок дати в інший формат, наприклад, так:

[[+mydate:strtotime:date=`%Y-%m-%d`]]

Прямий доступ до таблиці «modx_user_attributes» у базі даних з використанням вихідних модифікаторів замість сніпету можна здійснити просто шляхом використання модифікатора userinfo. Вибрати відповідний стовпець з таблиці та вказати його як властивість вихідного модифікатора, наприклад, так:

Внутрішній ключ користувача: [[!+modx.user.id:userinfo=`internalKey`]] Логін: [[!+modx.user.id:userinfo=`username`]] Повне ім'я: [[!+modx.user .id:userinfo=`fullname`]] Роль: [[!+modx.user.id:userinfo=`role`]] E-mail: [[!+modx.user.id:userinfo=`email`]] Телефон: [[!+modx.user.id:userinfo=`phone`]] Мобільний телефон: [[!+modx.user.id:userinfo=`mobilephone`]] Факс: [[!+modx.user.id :userinfo=`fax`]] День народження: [[!+modx.user.id:userinfo=`dob`:date=`%Y-%m-%d`]] Стать: [[!+modx.user .id:userinfo=`gender`]] Країна: [[!+modx.user.id:userinfo=`country`]] Штат: [[!+modx.user.id:userinfo=`state`]] Zip код : [[!+modx.user.id:userinfo=`zip`]] Фото: [[!+modx.user.id:userinfo=`photo`]] Коментар: [[!+modx.user.id:userinfo =`comment`]] Дата останнього входу: [[!+modx.user.id:userinfo=`lastlogin`:date=`%Y-%m-%d`]] Кількість входів: [[!+modx.user .id:userinfo=`logincount`]]

Особливу увагу звертаємо на знак оклику [[ ! +modx.user.id]]. Він дозволяє НЕ кешувативміст виводу. Чому потрібно не кешувати? Уявимо це так: на сайті 5 користувачів. Перший користувач зайшов на сторінку із викликом:

Ласкаво просимо, [[!+modx.user.id:userinfo=`username`]]!

За задумом на цій сторінці виводиться вітальне повідомлення користувачу. Так от, якщо результат кешуватиметься, то при першому вході на цю сторінку - збережеться ім'я користувача який тільки що зайшов - і решті буде показуватися не їх ім'я, а ім'я того користувача який увійшов на цю сторінку першим. Щоб цього уникнути, просто не кешуємо цей тег, за допомогою знака окликуперед викликом [[ ! +modx…

PS: Не забуваємо відключатикешування тегів, де потрібно! Щоб це зробити – потрібно ПОБУТАТИвід знаків оклику ( ! ). Результати більшості сніпетів цілком можуть працювати з кешу. У наступному уроці розберемо.

Вітаю, друзі! Сьогодні ми навчимося створювати фільтр ресурсів у MODx Revolutionз можливістю сортування за будь-яким TV полем та підвантаженням результатів по кліку "Завантажити ще". Для виведення результатів будемо використовувати сніпет pdoResources.

Класнути

Запинити

Завантажити всі сніпети та необхідні файли уроку.

Для початку необхідно встановити пакет pdoResources, що входить до складу пакету pdoTools. Ви можете встановити весь набір пакетів pdo (pdoTools) або тільки pdoResources окремим пакетом для створення фільтра на MODx Revolution.

Після встановлення пакетів, давайте підключимо сніппет, який ви завантажили у ваш проект. Якщо ви розробляєте каталог зараз з нуля, то раджу дотримуватись використання певних класів для Ajax фільтрації. Схема іменування класів:

Однак якщо у вас вже готовий каталог, ви можете визначити класи елементів Ajax фіьтра в JS файлі (див. нижче).

Зверніть увагу, що .ajax-itemмає бути безпосереднім нащадком .ajax-container. Якщо ви використовуєте сітку Bootstrap для розмітки колонок, можете визначити клас контейнера як "row ajax-container", а колонки айтема як "col-md-4 ajax-item".

Підключення JS скрипта Ajax фільтра

Підключимо скрипт JS до проекту. Ви можете підключити його як окремим файлом, так і безпосередньо до файлу кастомних скриптів проекту. Для роботи скрипта потрібний jQuery.

$(function() ( //MODx pdoResources Ajax Filter //Filter Settings var fadeSpeed ​​= 200, // Fade Animation Speed ​​ajaxCountSelector = ".ajax-count", // CSS Selector of Items Counter ajaxContainerSelector = ".ajax-container" , // CSS Selector of Ajax Container ajaxItemSelector = ".ajax-item", // CSS Selector of Ajax Item ajaxFormSelector = ".ajax-form", // CSS Selector Ajax Filter Form ajaxFormButtonStart = ".ajax-start", // CSS Selector of Button Start Filtering ajaxFormButtonReset = ".ajax-reset", // CSS Selector of Button Reset Ajax Form sortDownText = "За спаданням", sortUpText = "За зростанням"; function ajaxCount() ( if($(" .ajax-filter-count").length) ( var count = $(".ajax-filter-count").data("count"); $(ajaxCountSelector).text(count); ) else ( $(ajaxCountSelector ).text($(ajaxItemSelector).length); ) )ajaxCount(); response = $(response);$(ajaxCont ainerSelector).fadeOut(fadeSpeed); setTimeout(function() ( $(ajaxContainerSelector).html($response.find(ajaxContainerSelector).html()).fadeIn(fadeSpeed); ajaxCount(); ), fadeSpeed); )); ) $(ajaxContainerSelector).on("click", ".ajax-more", function(e) ( e.preventDefault(); var offset = $(ajaxItemSelector).length; $.ajax(( data: $(ajaxFormSelector) ).serialize()+"&offset="+offset )).done(function(response) ( $(".ajax-more").remove(); var $response = $(response); $response.find( $(ajaxContainerSelector).append($response.find(ajaxContainerSelector).html()); $(ajaxItemSelector).fadeIn(); )); )) $(ajaxFormButtonStart).click(function( e) ( e.preventDefault(); ajaxMainFunction(); )) $(ajaxFormButtonReset).click(function(e) ( e.preventDefault(); $(ajaxFormSelector).trigger("reset"); $("input" ).val("pagetitle"); $("input").val("asc"); setTimeout(function() ( $(")).data("sort-dir", "asc").toggleClass( "button-sort-asc").text(sortUpText); ), fadeSpeed), ajaxMainFunction(); ajaxCount(); )) $("").data("sort-dir", "asc").click(function() ( var ths = $(this) ); $("input").val($(this).data("sort-by")); $("input").val($(this).data("sort-dir")); setTimeout(function() ( $("").not(this).toggleClass("button-sort-asc").text(sortUpText); ths.data("sort-dir") == "asc" ? ths .data("sort-dir", "desc").text(sortDownText) : ths.data("sort-dir", "asc").text(sortUpText); $(this).toggleClass("button-sort -asc "); ), fadeSpeed); ajaxMainFunction(); )); ));

  • Рядки 5-13:визначення змінних для CSS селекторівФільтр Ajax. Не змінюємо, якщо використовуємо стандартні значення, як у малюнку вище;
  • Рядки 15-22:скрипт лічильника ресурсів у результатах фільтрації;
  • Рядки 24-35:основна функція Ajax фільтрації;
  • Рядки 37-49:обробник події на кліку на кнопку "Завантажити ще";
  • Рядки 51-54:обробник події на кліку на кнопці "фільтрувати". Ця кнопка може бути відсутній, оскільки фільтрація відбувається автоматично. Автоматична фільтрація може бути вимкнена шляхом видалення рядків 68-70;
  • Рядки 56-66:обробник події очищення форми та скидання фільтра. Рядки 59-63 відповідають за скидання параметрів сортування;
  • Рядки 68-70:функція автоматичного сортування за зміни полів форми фільтра;
  • Рядки 72-82:Універсальна функція сортування за tv параметром.

Я постарався зробити даний скриптмаксимально універсальним, тому якщо ви використовуєте стандартні селектори елементів фільтра Ajax, то редагувати ні чого не потрібно.

Підключення PHP сніпету в MODx Revolution

Створіть новий сніпет в панелі керування MODx catalogFilterі заповніть його таким вмістом:

=".$_GET["area_from"]; ) if($_GET["area_to"]) ( $filter = "area<=".$_GET["area_to"]; } //Checkbox Type if($_GET["garage"]) { $filter = "garage=1"; } //End Settings //Sort if($_GET["sortby"]) { $sortby = $_GET["sortby"]; } else { $sortby = "pagetitle"; } if($_GET["sortdir"]) { $sortdir = $_GET["sortdir"]; } else { $sortdir = "asc"; } //End Sort //Offset $offset = 0; if($_GET["offset"]){ $offset = $_GET["offset"]; } if($filter) { $where = $modx->доJSON(array($filter)); ) else ( $where = ""; ) $params_count = array("parents" => $parents, "limit" => 0, "tpl" => "@INLINE ,", "select" => "id", "includeTVs" => $fields, "showHidden" => "1", "where" => $where); $count = $modx->runSnippet("pdoResources",$params_count); $count = count(explode(",",$count))-1; $modx->setPlaceholder("count",$count); $params = array("parents" => $parents, "limit" => $limit, "offset" => $offset, "tpl" => $tpl, "select" => "id,pagetitle,introtext,content ", "includeTVs" => $fields, "showHidden" => "1", "sortby" => $sortby, "sortdir" => $sortdir, "where" => $where); $more = $count - $offset - $limit; $lim = $more > $limit? $limit: $more; $button = ""; if($more > 0)( $button = "
Завантажити ще ".$lim." з ".$more."
"; ) return $modx->runSnippet("pdoResources",$params).$button;

Між коментарями //Filter Fields Settingsі //End Settingsзнаходяться параметри, які необхідно відредагувати під свій проект. Тут нічого складного, просто прописуєте name полів input і перевіряєте їх умовою if. Для полів типу Radio, Select та Text використовуємо приклад із рядків 5-8. Для визначення проміжного значення від і до можна скористатися прикладом рядків 11-16. Для чекбоксів підійде приклад із рядків 19-21.

У рядку 74 сніппета ви можете задати свої класи, але не видаляйте поточну розмітку, оскільки вона бере участь у скриптах для навантаження контенту.

Приклад можливих значень на панелі керування MODx для радіокнопок: Перший==1||Другий==2||Третій==3


Приклад виведення радіокнопок на фронтенд:

Тут найменування name="floor"відповідає рядкам 6-8 нашого сніпета catalogFilter. Аналогічно реалізовано обробку інших полів форми. Я думаю, це зрозуміло і створення власних полів не буде для вас проблемою.

Виведення сніпету здійснюється в шаблоні каталогу таким чином:

[[!catalogFilter? &tpl=`tplCatItem` &limit=`3` &parents=`5` &fields=`image,area,floor,garage,price`]]

  • tpl=`tplCatItem`- чанк айтема у списку каталогу;
  • limit=`3`- Скільки записів виводити і скільки записів підвантажувати при кліку на кнопці "Завантажити ще";
  • parents=`5`- вказуємо id документа для каталогу ресурсів;
  • fields=`image,area,floor,garage,price`- перераховуємо TV"s, які необхідно показати в чанці tplCatItem і які необхідно обробляти при фільтрації.

Приклад чанка tplCatItem

[[+pagetitle]]

[[+tv.area:isnot=``:then=` `]]
Поверх [[+tv.floor]]
Площа [[+tv.area]] кв.м.
Гараж [[+tv.garage:is=`1`:then=`Є`:else=`Ні`]]
Ціна: [[+tv.price]]

Комплексний приклад виведення у фронтенд можете переглянути у репозиторії проекту на гітхабі у файлі demo.html.

Ajax сортування по TV

У нашому скрипті є готове рішення для сортування результатів фільтрації по будь-якому полю TV. У форму фільтра вставте наступні приховані поля і не змінюйте їх значення, вони просто повинні бути у формі фільтра:

У будь-якому місці вашого HTML шаблону зробіть висновок кнопки і в data атрибуті вкажіть поле, яким хочете фільтрувати видачу:

Сортувати за ціною: За зростанням

При кліку торкається клас button-sort-asc, який можете використовувати для оформлення кнопки при зміні напряму сортування, додавання стрілочок тощо в атрибут data-sort-byможна писати будь-який TV, що бере участь у фільтрації. Із сортуванням все.

Отже, ми розглянули створення нескладного Ajax фільтру ресурсів у MODx з виведенням результатів у СНІПЕТ pdoResources.

Всім доброго здоров'я. У цій статті я розповім, як зробити фільтр документів за tv-параметрами на сайті під управлінням Modx Revolution. Ми будемо використовувати сніппет tagManager2від Andchir. Цей сніпет вміє працювати відразу з декількома tv, а також з числовими даними (у вигляді ціни) та множинним списком. Кожен цей приклад ми розберемо далі.

1. Для початку потрібно встановити tagManager2

Для цього йдемо в Програми/Установник/

тиснемо кнопку "Завантажити доповнення"і в рядку пошуку вбиваємо tagManager2

Також ще потрібно встановити сніпет getPage та getProducts. Таким чином розділ «Керування пакетами»має виглядати так (сніппет translit, до речі, відповідає за транслітерацію псевдонімів на латиницю)

Завантажуємо, встановлюємо пакети та йдемо в «Налаштування системи»

2. Налаштовуємо сніпет tagManager2

У Системних налаштуваннях вибираємо розділ tag_manager2

Ми побачимо параметри налаштування фільтра

Там все досить просто і зрозуміло, але все ж таки:

  • У "ID ресурсу каталогу верхнього рівня"вказуєте id шаблону каталогу чи категорії, де фільтруватимуться товари чи сторінки
  • У «Додатковий роздільник множинного списку»ставимо знак #. Нижче ви дізнаєтеся навіщо він потрібний
  • У «Імена TV або полів із множинним списком»прописуємо tv із множинним списком. Як їх створити я покажу нижче
  • "Імена TV або полів з числовими значеннями"- тут потрібно вказати tv-параметри, де будуть цифри. Зазвичай, це параметр ціни. Цей фільтр буде виведений у вигляді повзунка «від і до»
  • У "ID шаблонів товарів"прописуємо id сторінок, які потрібно фільтрувати та до яких прикріплені tv-параметри, вказані вище
  • У "Ім'я набору параметрів, що використовується для фільтрації"прописуємо catalog_filters Цей шаблон ми будемо використовувати у шаблонах параметрів getPageі getProducts
  • Прописати в "Сніппет пов'язаний з набором параметрів"назва сніпета, який здійснюватиме виведення та пагінацію сторінок або товарів. Зазвичай це getPage.

3. Створюємо набір параметрів catalog_filters у getPage

Ідемо в сніпет getPage

Переходимо у вкладку «Параметри»та натискаємо на кнопку «Додати набір параметрів». Можна, звичайно, й відредагувати існуючий, але тоді є шанс затирання параметрів, які ми зараз створимо при оновленні getPage. Якщо не збираєтеся оновлювати, можете просто редагувати.

Редагуємо існуючі параметри та присвоюємо значення:

Створюємо нові параметри та присвоюємо значення

Відредаговані параметри відображатимуться зеленим кольором, створені – фіолетовим.

4. Створюємо або редагуємо tv параметри для фільтра

Я створив для прикладу 3 tv-параметри

Особливу увагу хочу привернути до того, що потрібно вказувати Ім'я (Заголовок) tv-параметра, інакше він може просто не відображатися в модулі управління фільтрами

5. Створюємо чанк filtr_tpl

Цей чанк відповідає за виведення кожного окремого результату в getProducts

6. Створюємо структуру у дереві документів

У мене вона виглядає так:

Головна сторінка у нас з ID 1, а у товарів id шаблону 1 (це у нас стоїть у налаштуваннях tag_manager2, якщо у Вас інші значення, не забудьте поміняти в налаштуваннях)

7. Редагуємо filters.js

Ідемо за адресою /assets/components/tag_manager2/js/web/filters.jsі замість

Multitags: ["tags"], / / ​​Імена дод. полів з множинними значеннями

вставляємо код із нашими підставленими значеннями

Multitags: ["filtr1", "filtr2"], / / ​​Імена дод. полів з множинними значеннями

Тут все дуже просто і зрозуміло. Ми вставили свої tv поля з множинними значеннями. А взагалі це конфіг усіх налаштувань (але краще без дозволу великих дядечок їх не чіпати, я маю на увазі порад творців модуля)

8. Виводимо фільтр та результати фільтрації

Сам фільтр

[]
[[+filters]]

Виведення результатів з пагінацією

[[!tmCatalog]]
    [[!+page.nav]]

Сортування результатів

9. Активуємо фільтр

Тепер потрібно лише активувати наш фільтр. Для цього йдемо в Програми/Керування фільтрами.

Тут потрібно поставити галочки біля кожного фільтра та натиснути кнопку"Зберегти" .

Якщо ви все зробили правильно, фільтр повинен заробити. На цьому все. Якщо з'явилися питання – ставте у коментарях, постараюся відповісти. А взагалі ось документація по tagManager2. Успіхів у розробці. У "Демо"один із моїх сайтів, на якому реалізований фільтр за допомогою tagManager2

© 2022 androidas.ru - Все про Android