«phpClub» — архив тем ("тредов"), посвящённых изучению PHP и веб-технологий.
someApprentice 2018/04/11 12:15:16  №1171609 1
https://jsfiddle.net/5bkb5gk5/
https://github.com/richBlueElephant/phpClub/issues/21#issuecomment-380116215

>Для того, чтобы отлавливать клики с фильтром по определенному селектору, есть $.on: http://api.jquery.com/on/
От такого способа пришлось отказаться, потому что нужно чтобы при клике снаружи привью оно убралось.

Кстати, проверка чтобы при клике на само привью оно не убиралось не сработала.

if (!$('.fullsize').is(e.tareget)) { //somehow it doesn't works
$(lightbox).hide();
$(lightbox).empty();
}

У вас есть мысли почему?

>Для проверки, что мы кликнули на элемент, лучше всего использовать $.on, или конструкцию $(target).closest('.file a').length - она делает поиск от элемента к корню дерева. Опять же, вместо сложного селектора тут лучше было бы вписать только один класс.
>
>Еще есть $(target).is('.file a') - но она проверяет на точное совпадение с селектором.
Не совсем понимаю о чем идет речь. У меня же и так идёт проверка !$(a).is(e.target).

И зачем нужно искать ближайщую ссылку от цели? Это же можно будет кликнуть в любом месте поста и откроется привьюшка.

>На все ключевые элементы поставить свой класс. Для выбора названий классов лучше всего (по моим ощущениям) использовать БЭМ, а в верстке макабы классы расставлены от балды без всякой логики.
Я переработал и HTML разметку, однако, на некоторых вложенных элементах не стоят классы. Согласно именованию в БЭМ, в каждом элементе должно быть и имя блока, в котором он содержится. В идеале нужно переработать и это?

Ключевым элементом имеется ввиду, элемент, с которым мы работаем или будем работать?

>default:
>window.open(src, '_blank');
>
>Это вообще наверно писать не надо, лучше просто выйти из обработчика, не отменяя действие по умолчанию.
Если убрать отмену действия по умолчанию, то каждый раз, даже при открытии привью, картинка будет открываться в новой вкладке. Есть какой-то другой способ избежать этого?

>$(content).ready
>
>Вообще, центрирование идеальнее всего сделать средствами CSS (через position: absolute, table-cell либо flexbox, последний умеет ужимать картинку до размера контейнера), либо, если невозможно, то надо ловить события load/error на картинке, а не ready.
>Кстати, при изменении размера окна надо перецентрировать картинку заново. Потому лучше было бы поискать способы центрировать ее через CSS.
У меня не получилось отцентрировать по вертикали абсолютно позиционированный элемент https://jsfiddle.net/5zgteu99/

>preventDefault лучше делать только, если мы успешно обработали клик, а не всегда.
А как выполняющая preventDefault функция выполниться, если обработка не прошла успешно?

>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
А разве клика за пределами привьею не достаточно?

>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
Ответы: >>1172045 >>1172046 >>1172048
Аноним 2018/04/12 03:25:53  №1172046 2
>>1171609

> if (!$('.fullsize').is(e.tareget)) { //somehow it doesn't works
Там написано e.tareget.

Но вообще, ты неправильно делаешь сравнение, надо либо $(target).is(..) либо $(target).closest(), а ты делаешь поиск по всему дереву DOM ради одного сравнения.

И не надо писать $() вокруг переменной lighbox, если это и так объект jQuery.

> От такого способа пришлось отказаться, потому что нужно чтобы при клике снаружи привью оно убралось.

Это проще всего реализовать, подложив под превью прозрачный див. Ну хотя можно и проверять через is()/closest().

Также, не надо делать поиск элементов в DOM каждый раз. Проще в начале скрипта их найти и потом обращаться к этой переменной. Например, элемент #lightbox нет смысла каждый раз искать заново.

>>Еще есть $(target).is('.file a') - но она проверяет на точное совпадение с селектором.
> Не совсем понимаю о чем идет речь. У меня же и так идёт проверка !$(a).is(e.target).

Потому, что у тебя сделано неэффективно. Вот как у тебя сделано:

// запускаем обход всего огромного дерева DOM и получаем массив из сотни-двух ссылок
var a = $('a', '.file');

// Проверяем, есть ли target в этом списке, после чего отбрасываем список.
if ($(a).has(e.target).length == 0 && !$(a).is(e.target)) {

То есть ты ради проверки делаешь поиск по всему дереву DOM, и почти сразу же отбрасываешь результат. При каждом клике по странице. Это неэффективно.

Я предлагаю не делать поиск по всему дереву DOM, а просто сделать $(target).is(...). Что очевидно эффективнее. Если в селекторе указан просто класс is('.something'), то эта проверка сводится к проверке класса у текущего элемента.

closest() нужен в том случае, если мы хотим отслеживать клик по элементу, у которого есть дети. Так как клик может попасть на кого-то из детей, а не на родительский элемент. Ну например:

<div class="x">
<div class="y"></div>
<div class="z"></div>
</div>

Допустим, мы хотим проверить, был ли клик по элементу .x (или его детям). Мы можем написать так:

var isClicked = $(target).closest('.x').length > 0;

Такой код вернет true, если мы кликнули в .x, в .y или в .z.

> Я переработал и HTML разметку, однако, на некоторых вложенных элементах не стоят классы. Согласно именованию в БЭМ, в каждом элементе должно быть и имя блока, в котором он содержится. В идеале нужно переработать и это?

Нет, не совсем так. В БЭМ мы выделяем "независимые" блоки, которые могут быть в том числе вложены друг в друга. Например: пост, превьюшка, шапка, подвал, меню итд. Для них назначаем какие-то имена. А для их неотъемлемых частей (элементов) делаем имена с использованием имени блока. Ну например, у поста есть элемент "дата", который не является независимым, а является неотъемлемой частью поста. Для него мы сделаем имя вроде post__date. Из которого и видно, что это часть блока post.

"Независимый" - значит, что блок можно поместить в любое место любой страницы и он будет корректно отображаться и работать (при наличии достаточного места). Независимый блок не зависит от наличия каких-то родительских элементов или классов на них.

> Ключевым элементом имеется ввиду, элемент, с которым мы работаем или будем работать?
Ну я имел в виду, такие части страницы, как пост, тред, и тд. То есть то, что приходит в голову, когда пытаешься разбить страницу на блоки.

> Если убрать отмену действия по умолчанию, то каждый раз, даже при открытии привью, картинка будет открываться в новой вкладке.
Отменять действие, только если мы приняли решение показать картинку на странице. А не в любом случае вообще.

> А как выполняющая preventDefault функция выполниться, если обработка не прошла успешно?
надо убрать эту отдельную функцию и поместить preventDefault в основную функцию.

>>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
> А разве клика за пределами привьею не достаточно?

А как догадаться, что можно кликнуть за пределами?

>>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
> Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
А зачем выделять текст во время просмотра картинки? Я об этом конечно не думал.

Ответы: >>1172863
Центрирование в CSS Аноним 2018/04/12 03:34:25  №1172048 3
>>1171609

> У меня не получилось отцентрировать по вертикали абсолютно позиционированный элемент

> position: absolute;
> display: table-cell;
Эти стили вообще не совместимы. Нельзя ячейку таблицы спозиционировать абсолютно. Ее положение определяется таблицей, ячейку нельзя вырвать из нее. Также, кстати, нельзя позиционироваться относительно ячейки или другой части таблицы.

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

Вообще, способы решения делятся в зависимости от ситуации. Я сделал несколько примеров кода тут https://codepen.io/anon/pen/LdvNdW для тех методов, где код не очевиден.

задан размер контента (WxH), неизвестен размер контейнера

1) Можно сделать у контейнера pos:rel, у контента pos:abs, left/top/right/left: 0, margin: auto; height: H; width: W; - здесь margin будет вычислен из top, bottom, height. Объяснение на англ: https://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height

2) Можно сделать у контейнера pos:rel, у контента pos:abs, top: 50%, margin-top: -(H/2)px; height: H; . Это работает с CSS2.1, если хочется ограничить себя новыми CSS3 браузерами, можно писать top: calc(50% - H/2px);

задан размер контейнера (WxH), неизвестен размер контента

1) Можно сделать в контейнере height: H; lihe-height: H;, в контенте: display: inline-block; line-height: 16px; (восстанавливаем назад) . Теория https://www.w3.org/TR/CSS2/visuren.html#inline-formatting

неизвестны ни размер контейнера, ни контента

1) Поместить картинку на фон (в background-image) и центрировать за счет background-position: 50% 50%; Ограничить ее размер можно с помощью background-size.

+ Поддерживается с давних времен: https://caniuse.com/#search=background-size (даже в IE8 за счет AlphaImageLoader)
+ Поддержка bg-size: IE 2011+, FF 2010+, Chrome 2010+, Opera 2009+, Android 2009
+ Если background-size не поддерживается, отобразится центр картинки в масштабе 1:1
+ Не вырезается почтовыми сервисами вроде gmail (почтовые сервисы фильтруют и HTML, и CSS в письмах)
- Маленькие картинки увеличиваются и размываются
- Нет поддержки srcset


2) Центрирование за счет translate

Это разновидность описанного выше трюка с абс. поз, но тут вместо ручного задания margin-top мы используем translate, который позволяет считать проценты от размера контента. Мы позиционируем содержимое с помощью top: 50%; left: 50%; (проценты относительно размера контейнера), а затем сдвигаем его в центр за счет translate(-50%, -50%) - тут проценты уже от размера содержимого.

Поддержка: https://caniuse.com/#search=translate
+ Поддержка с префиксами IE9 (2011), FF 2009, Chrome 2010, Opera 2011, Android 2009
+ Маленькие картинки центрируются и не увеличиваются
- Если transform не поддерживается, будет видна 1/4 картинки
- Почтовые сервисы не пропускают transform

Теория https://www.w3.org/TR/css-transforms-1/#terminology

3) Двойное translate

Здесь мы усложняем схему, чтобы в браузерах, не поддерживающих translate, показывалась бы не 1/4, а верхняя часть картинки. (хорошо бы конечно его протестировать получше, так как я не уверен что он 100% рабочий).

Поддержка: https://caniuse.com/#search=translate
+ Поддержка с префиксами IE9 (2011), FF 2009, Chrome 2010, Opera 2011, Android 2009
+ Маленькие картинки центрируются и не увеличиваются
+ Если transform не поддерживается, будет видна верхняя часть картинки вместо середины
+ Картинка влияет на высоту блока, которая может ограничиваться через min/max-width либо задаваться фиксированной через width
+ Можно добавить img { max-height: Npx; } , чтобы высокие картинки тоже помещались в блок
- Наибольший объем кода
- Не работает (картинка не центрируется) в mail.ru, yandex.ru, gmail.com из-за того, что почтовые сервисы не пропускают свойство transform

4) table

Контейнеру ставим display: table, в нем делаем див с display: table-cell; vertical-align: middle; text-align: center; и в него кладем картинку.

Теория https://www.w3.org/TR/CSS2/tables.html#height-layout

Минус: не уверен, что будет работать ограничение по высоте, так как содержимое таблицы может ее растягивать.

5) flexbox

Лень разбираться в спецификации, но он мощнее предыдущих методов. Однако, требует поддержки flexbox в браузере. В теории можно попробовать написать код с флексбокс и сделать фоллбек на какой-то другой метод для более старых браузеров.

Ответы: >>1172863
someApprentice 2018/04/13 13:49:16  №1172863 4
>>1172046
>>>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
>> А разве клика за пределами привьею не достаточно?
>
>А как догадаться, что можно кликнуть за пределами?
Добавил крестик и закртыие по ескпейпу. Только крестик на тёмном фоне плохо видно (посмотреть можно уже на сайте). Как это исправить?

>>>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
>> Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
>А зачем выделять текст во время просмотра картинки? Я об этом конечно не думал.
Конечно на практике я такое не делал, но мне показалось, что не хорошо получается, когда сама картинка занимает всего лишь какую-то часть страницы, а не деле всю. Это не более чем "косметическое" исправление.

>>1172048
Спасибо за предоставленные способы - я возьму их себе на заметку.

Если #lightbox лежит в body, то body будет контейнером. Не слишком ли опасно проводить на теле такие операции?

Я правильно понимаю, что все эти способы подразумевают, что контейнер это подкладка, или, быть может, контейнер лучше будет поместить в подкладку? Я только не понимаю, мы центрируем элемент относительно окна, это значит, что размер заданный в процентах или flexbox/table на body, не позволит воспользоваться большинством способов. В нашем случае, наилучшим способом будет двойной translate.


Я, если честно, плохо понимаю вёрстку. К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить https://jsfiddle.net/kd5bqr4j/1/

Так же, я не понимаю как в макабе сделан отступ конетнта от единичной картинки. Я прошелся вверх по дереву DOM от самой картинки и контенту, и отключал CSS свойства, и это не как сломало этот отступ. У меня только получилось чтобы текст только обтекал картинку https://jsfiddle.net/ntq1mqfL/ .

И с такими проблемами я сталкиваюсь всё время.
Наверно, мне лучше прочитать и выучить спецификации.

Если у вас будут какие-то ещё замечания - буду рад их услышать.
Спасибо
Ответы: >>1172951 >>1173384
Аноним 2018/04/13 20:59:28  №1173143 5
Добрый вечер, аноны. У меня такой вопрос возник. Какие курсы можно закончить чтобы было чем хоть при устройстве на работу посветить. Высшее образование у меня неоконченное, 3 курса юридического. Им особо не посветишь. Я понимаю что знания нужно получить самому. Но есть ли хоть какие-то действительно хорошие долгие курсы по фронтенду которые ценятся при приеме на работу? Желательно конечно удаленно, но если есть что-то достойное только очно, то я бы и его прошел. Анон спаси, все курсы которые гугл выдает оказываются тратой времени и денег, если гуглить отзывы о них.
Ответы: >>1173171
Аноним 2018/04/13 21:35:53  №1173171 6
>>1173143
> все курсы которые гугл выдает оказываются тратой времени и денег, если гуглить отзывы о них.
Так и есть. Твою профпригодность определяют реальные навыки, гитхаб, портфолио, а лёгких путей для вкатывания нет. Ты где-то видел, чтобы юристов готовили на курсах? У тебя для обучения есть бесплатные книги в огромном количестве и обучающие платформы интерактивные, но нет, хочу платить за курсы, вот я заплачу, а меня научат. Так не работает.
Ответы: >>1173182
Аноним 2018/04/13 21:46:20  №1173182 7
>>1173171
Да я же сказал, что сам обучаюсь. Я хочу курс именно для бумажки которой при устройстве можно похвастать, вот и все. Я не собираюсь идти на курсы за знаниями.
Ответы: >>1173194
Аноним 2018/04/13 21:58:43  №1173194 8
>>1173182
Создай что-нибудь годное и залей на гитхаб, гораздо полезнее чем тратить деньги на говнокурсы. Если стыдно указывать в резюме неоконченное высшее, напиши что еще учишься на заочке, кто это будет проверять?
Ответы: >>1173209
Аноним 2018/04/13 22:11:59  №1173209 9
>>1173194
Ну то есть ни одного курса который бы дал хоть сколько-то ценную бумажку или что-то достойное в портфолио, нет?

Еще раз повторю, что прекрасно понимаю что знания я получу сам и к ним исключительно иду за тем чтобы было какой бумажкой посветить при устройстве.
Ответы: >>1173384
Аноним 2018/04/14 04:42:45  №1173384 10
>>1173209

Если тебе нужна бумажка, получи диплом в вузе. А так я не уверен, что какие-то краткосрочные курсы произведут впечатление. Хотя конечно зависит от HR.

То, что ты придумал, глупо. На курсы идти нужно именно за знаниями, иначе это просто трата денег.

>>1172863

Я бы еще советовал глянуть существующие плагины для просмотра картинок (конечно, куча кнопок и функций не нужна, но можно посмотреть, как они сделаны). Они часто называются вроде lightbox:

- http://ignitersworld.com/lab/imageViewer.html
- http://lokeshdhakar.com/projects/lightbox2/
- http://fancyapps.com/fancybox/3/
- https://fengyuanchen.github.io/viewerjs/
- https://noelboss.github.io/featherlight/
- http://dimsemenov.com/plugins/magnific-popup/
- https://sorgalla.com/lity/

Этих скриптов так много, что я даже не знаю, какой лучше или хуже.

> Посмотреть можно на сайте

Ну пока какие-то косяки, например: https://i.imgur.com/JCuEhn9.jpg

Очевидно, тут проблема в том, что скрипт пытается определить размер картинки до ее полной загрузки, определяет неверно и все раскособочило.

> Только крестик на тёмном фоне плохо видно
Я его вообще не вижу. Но чтобы его было видно, можно использовать один из вариантов:

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

> и закртыие по ескпейпу
А он кстати перехватывает эскейп только когда открыта картинка и не перехватывает в других случаях?

> Если #lightbox лежит в body, то body будет контейнером. Не слишком ли опасно проводить на теле такие операции?
Не опасно, но естественно, добавление стилей на body повлияет на верстку. Да и лучше наверно сделать контейнером div c pos: fixed, left/right/top/bottom: 0; Или нет?

> Я правильно понимаю, что все эти способы подразумевают, что контейнер это подкладка, или, быть может, контейнер лучше будет поместить в подкладку?
В моем посте контейнер - это блок, внутри которого находится контент (картинка), которую мы центрируем. Ну например, у тебя контейнером может быть div c pos: fixed, top/bottom/left/right: 0; и внутри него мы центрируем картинку.

> Я, если честно, плохо понимаю вёрстку.
Ну ты задавай вопросы, я подскажу.

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

Если открыть отладчик в браузере, то мы увидим:

> #lightbox {
> max-height: 66%;

Соответственно лайтбокс из-за этого оказывается меньше, чем картинка. На картинке, конечно, стоит height: 100%;, но это свойство тут не работает, так как высота лайтбокса не задана явно в CSS. Если мы откроем спец-ю по height, то там написано:

> https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#the-height-property
> <percentage>
> If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.

Высота в процентах работает только если высота родителя явно задана, например в пикселях, или в процентах от прародителя, у которого в свою очередь тоже задана высота. Исключение - абс. поз. элементы, для них можно задавать высоту в процентах в любом случае (так как абс. поз. эл. никак не влияет на родителя и его высота вычисляется после того, как высота родителя посчитана).

Это, к сожалению, не очень известная особенность CSS.

> Так же, я не понимаю как в макабе сделан отступ конетнта от единичной картинки.

Есть один трюк. Если ты помещаешь перед текстом картинку с float, то текст (и любые inline/inline-block элементы) ее обтекает справа и снизу. Но если ты засовываешь текст в блок с overflow: auto, то этот блок сдвигается вправо как одно целое, плюс его ширина магическим образом вычисляется так, чтобы занять все свободное место: https://codepen.io/anon/pen/Brgyza

При этом, если например, вместо overflow: auto влепить просто display: inline-block или float: left, то ничего не работает - текст проваливается под флоаты (так как блок слишком большой, чтобы уместиться сбоку).

И что интересно, хотя для .text по идее должна по умолчанию вычисляться ширина в 100% (так как он display: block, не float, не абс. поз.), здесь за счет какой-то магии ширина уменьшается.

Я решил поискать это в спец-и: https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#floats

> The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.

Если что, replaced elements - это картинки, элементы форм, то есть элементы, у которых есть внутренний размер.

Здесь указано, что float не должен пересекаться с:

1) таблицами
2) block-level replaced element (например: картинка с display: block)
3) element in the normal flow that establishes a new formatting context

В такой ситуации разрешается 2 варианта:

a) сдвинуть элемент под флоат
b) поместить элемент сбоку от флоата, ужав его ширину

А далее начинаются странности. Если мы посмотрим на пункт 3, и поищем, что может создавать "new formatting context", то увидим: https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#block-formatting

> Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.

Поскольку "float, absolutely positioned elements" не попадает под условие "in normal flow" в пункте 3, мы их отбросим. Остается:

x) block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes
y) block boxes with 'overflow' other than 'visible'

По логике, и x) и y) должны себя вести одинаково. Но по факту элементы из пункта x) проваливаются под флоат по варианту a), а вот элементы из пункта y) ужимаются по ширине по варианту b).

Объяснить это, думаю, можно историческими причинами, какой-то браузер ужимал блоки с overflow по ширине, сайты были сверстаны с учетом этого, и в спецификации решили зафиксировать такую возможность, но не указывать, как именно должен себя вести браузер.

Это показывает интересную особенность: если ты напишешь новый браузер строго по спецификации, многие сайты в нем развалятся. Так как люди верстают не по спецификации, а на глаз, опираясь на поведение существующих браузеров и на такие неявные особенности. А сама спецификация не описывает все на 100%.

Я еще глянул спецификацию CSS2.0 и там в разделе floats такое не описано. Скорее всего, где-то между CSS2.0 и 2.1 браузеры это реализовали, и пришлось зафиксировать это в спецификации по факту.

И еще, я нашел тред в рассылке w3c: https://lists.w3.org/Archives/Public/www-style/2008May/0225.html
- там упомянуто, что сайты полагаются на эту особенность (по-видимому, добавленную в старом IE).

Надеюсь, загадка раскрыта. Я давно знал про эту особенность, но не знал, описана ли она где-то и откуда взялась.

> Наверно, мне лучше прочитать и выучить спецификации.

Я обычно туда смотрю только в спорных случаях. Вот те случаи, что ты упомянул, как раз без спецификации не разобрать, они довольно хитрые.

По коду:

Не забывай кроме событий img.load/video.canplay обрабатывать ошибки - ошибка загрузки, отсутствие поддержки формата браузером

Вместо $(content)[0].oncanplay наверно можно писать $(content).on('canplay') - нет?

var a = $('.file-link'); - это, как мне кажется, не нужно.

var fullsize = $('.fullsize'); - вместо поиска каждый раз заново в дереве DOM было бы удобнее просто хранить ссылку на элемент в переменной.

hideLightbox не надо вызывать, если он уже закрыт.

Вместо $(e.target).closest(a) наверно надо было написать closest('a'). Там указывают селектор обычно.

Вместо $(target).is мне кажется, лучше использовать closest(), так как клик может придтись как на элемент <a>, так и на <img> внутри него.
Ответы: >>1173471
someApprentice 2018/04/14 12:04:09  №1173471 11
>>1173384
>Я бы еще советовал глянуть существующие плагины для просмотра картинок (конечно, куча кнопок и функций не нужна, но можно посмотреть, как они сделаны). Они часто называются вроде lightbox:
Я до этого только догадывался как работает popup. Поэтому, я нашел один из перечисленных плагинов, посмотрел принцип его работы, а так же посмтрел как это работает в популярных соц.сетях, и написал свой под свои нужды.

>Этих скриптов так много, что я даже не знаю, какой лучше или хуже.
Который ты написал сам https://i.imgur.com/4QwBnwK.gif

>> Посмотреть можно на сайте
>Ну пока какие-то косяки, например: https://i.imgur.com/JCuEhn9.jpg
>Очевидно, тут проблема в том, что скрипт пытается определить размер картинки до ее полной загрузки, определяет неверно и все раскособочило.
Почему вы решили что проблема в этом? Проблема в том что картинка выходит за пределы контейнера#lightbox.

>> Только крестик на тёмном фоне плохо видно
>Я его вообще не вижу.
Нужно навести на картинку.

Я не подумал, что пользователь может не пользоваться мышью, например на ноутбуке. Я вообще не очень люблю когда элементы интерфейса бросаются в глаза, они отвлекают от самой картинки т.е. от контентной части. Я обратил внимание, что во все перечисленных lightbox плагинах, этот крестик присутствует, но пойти на такой шаг мне даётся кривя душой. Разве не достаточно будет выхода по ескейпу в таком случае?

Аргументируйте, пожалуйста, почему крестик нужно сделать видимым всегда, и, может быть, мне будет легче это сделать.

>> и закртыие по ескпейпу
>А он кстати перехватывает эскейп только когда открыта картинка и не перехватывает в других случаях?
Я сделал проверку if (lightbox.css('display') == 'block') { , но сейчас загуглил и понял что лучше сделать проверку .is(':visible'). Это хороший способ?

https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L97

>> К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить
>Высота в процентах работает только если высота родителя явно задана, например в пикселях, или в процентах от прародителя, у которого в свою очередь тоже задана высота. Исключение - абс. поз. элементы, для них можно задавать высоту в процентах в любом случае (так как абс. поз. эл. никак не влияет на родителя и его высота вычисляется после того, как высота родителя посчитана).
Так как быть? Я не могу явно указать ширину или высоту контейнера, т.к. он растянется шире картинки, а нужно чтобы контейнер был не больше 66% страницы и картинка вписывалась в него, либо чтобы сама картинка была не больше 66% а размер контейнера высчитался из содержимого. Я не понимаю что тут можно сделать.

>По коду:
>var a = $('.file-link'); - это, как мне кажется, не нужно.
Почему не нужно? Мы в пару местах делаем проверку на этот элемент. Нужно каждый раз их искать?

https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L37
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L44

>var fullsize = $('.fullsize'); - вместо поиска каждый раз заново в дереве DOM было бы удобнее просто хранить ссылку на элемент в переменной.
Этот элемент нужно искать именно каждый раз когда мы делаем клик, потому что, при каждом открытии, он, каждый раз, создаётся новый.

https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L49
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L58

>Вместо $(e.target).closest(a) наверно надо было написать closest('a'). Там указывают селектор обычно.
Можно и объект jQuery указать, и элемент DOM...

https://api.jquery.com/closest/#closest-selection
Ответы: >>1173472 >>1176471
Аноним 2018/04/19 06:33:55  №1176471 12
>>1173471

> Почему вы решили что проблема в этом? Проблема в том что картинка выходит за пределы контейнера#lightbox.

Да, я ошибся. Проблема там в том, что height 66% не работает.

> Аргументируйте, пожалуйста, почему крестик нужно сделать видимым всегда, и, может быть, мне будет легче это сделать.

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

Ну и на мобильных устройствах нет "наведения мыши".

Кнопки должны быть видны, это однозначно. Крестик можно при желании поместить снаружи картинки.

> Я сделал проверку if (lightbox.css('display') == 'block') { , но сейчас загуглил и понял что лучше сделать проверку .is(':visible'). Это хороший способ?

Да, однозначно, так как есть много вариантов скрыть элемент, кроме display: none. Например: поставить display: none на родителе.

Также, еще мне нравится идея просто хранить состояние попапа в переменной, а не лезть за ним в DOM.

Что еще мне не нравится - то, что у тебя весь скрипт - гигантская анонимная функция, которая засунута в $().ready(). Вот как это читать? Читатель, по твоему, должен терпеливо прочесть все 160 строк сверху донизу (это пока их 160, а дальше будет больше)? Это неудобно. Гораздо лучше разделить отдельно функции и отдельно код инициализации.

Также, мне вообще не нравится идея "самозапускающихся скриптов". Мне нравится идея, когда JS скрипт - это модуль, просто набор определений (классов, функций) и в нем само собой ничего не запускается. Твой подход на больших сайтах приводит к тому, что все только дописывают код в ready() и мы имеем функции на тысячи строк, причем там большая часть кода не нужна на текущей странице, но все равно выполняется, и никто не может понять, какая часть кода еще используется, какая уже не нужна. И потому код только копится и растет со временем.

То есть это выглядит как:

$(...).click(.... 100 строк ...);

$(...).hover(.... 50 строк ...);

И так несколько десятков блоков подряд.

Также, такой подход приводит к тому, что глядя на HTML-код страницы, невозможно понять, какие к нему привязаны обработчики - они спрятаны где-то в тысячах строк кода в ready().

Какие ты видишь решения проблемы?

> $(window).scroll(function() {
Это не очень хорошая идея, надо бы хотя бы троттлить тут вызов функции, а то при плавном скроллинге твоя функция будет вызываться с большой частотой и нагружать браузер постоянным обновлением дома. Вообще, функции , которые вешаются на scroll - это зло для производительности (особенно на мобильных):

- https://developers.google.com/web/updates/2016/06/passive-event-listeners
- http://joji.me/en-us/blog/how-to-develop-high-performance-onscroll-event
- https://www.sitepoint.com/throttle-scroll-events/
- https://www.html5rocks.com/en/tutorials/speed/scrolling/

> if ($(a).has(e.target).length == 0 && !$(e.target).is('.file-link')) {
Еще раз спрошу, а почему не использовать тут closest() или is() вместо has() и поиска кучи узлов?

Плюс, в твоем коде есть недостаток, что var a = $('.file-link'); не содержит добавленные позже в DOM узлы. Например, картинки из постов, подгруженных через аякс.

> var fullsize = $('.fullsize');
Не лучше ли сохранять ссылку в переменной, а не искать каждый раз этот класс по всему дереву DOM?

Ну и не вижу обработку ошибок. Также, хорошо бы добавить прелоадер, хотя бы текст "загрузка...".

> Так как быть? Я не могу явно указать ширину или высоту контейнера, т.к. он растянется шире картинки, а нужно чтобы контейнер был не больше 66% страницы и картинка вписывалась в него, либо чтобы сама картинка была не больше 66% а размер контейнера высчитался из содержимого. Я не понимаю что тут можно сделать.

Ну давай искать варианты и тестировать. Я для затравки подкину пару идей, а ты их потестируй в разных условиях и браузерах:

1) https://codepen.io/anon/pen/yjyLyP

Тут главная идея в том, что мы позиционируем картинку внутри контейнера абсолютно и за счет этого получаем возможность использовать max-height, а также центрирование за счет margin-auto. Перечитай спец-ю про abs pos, если что-то непонятно:

- https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#abs-replaced-width
- https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#abs-replaced-height

Ограничение в 66% мы делаем за счет жесткого задания размера контейнера. Но я поймал себя на мысли, что можно было сделать контейнер на все окно, а ограничение сделать заданием max-height: 66% либо top/bottom: 17% на картинке.

Вообще, я надеюсь, что цифра 66% условная, так как при ней не используется значительная часть экрана.

2) зловещий flexbox https://codepen.io/anon/pen/GdgRjo?editors=1100

Подвохи с ним - он не везде поддерживается и там много тонкостей. Например, у меня в фаерфоксе раскособочило картинку 800x200 (ее ужало до 400x200 с нарушением пропорций), хотя в Хроме тот же код работал как надо и она уменьшается. То ли я неправильно что-то сделал, то ли баг, то ли еще что-то. Не хочешь помучаться и выяснить?

3) https://codepen.io/anon/pen/WJbNKM?editors=1100

Тут мы позиционируем картинку ниже середины (top: 50%) и сдвигаем ее вверх на середину за счет translate. Так как картинка позиционирована абсолютно, мы можем применять max-height в процентах.

Минус - я не придумал в этих методах, как тут завернуть картинку в обертку. А обертка нужна, если мы например, хотим поместить крестик в углу или подпись к картинке - нам нужна обертка, равная по размеру картинке. Но если мы добавим обертку, перестанет работать max-height на картинке. А если мы спозиц. картинку абсолютно внутри обертки, то картинка перестанет растягивать ее. Замкнутый круг.

Что-то мне кажется, для добавления обертки надо опять откатываться к яваскрипту. Либо добить решение с флексбоксом. Вот такой вот он, CSS. Предлагай свои идеи.

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

- яваскриптом вычисляем размеры картинки
- ограничиваем их с учетом размеров окна
- ставим их на контейнер как width/height
- центрируем/ограничиваем размер за счет CSS

Мне кажется, это лучше будет работать при изменении размеров окна, например. Вот пример: https://codepen.io/anon/pen/MGYWLZ?editors=1100 - тут специально добавлена желтая обертка, чтобы показать, что контейнер пропорционален картинке.

> Почему не нужно? Мы в пару местах делаем проверку на этот элемент. Нужно каждый раз их искать?

Использовать вместо этого is()/closest() и ничего не искать.

> Этот элемент нужно искать именно каждый раз когда мы делаем клик, потому что, при каждом открытии, он, каждый раз, создаётся новый.
ну все равно, можно сохранять ссылку на него, а не искать в DOM.
Ответы: >>1176480 >>1178355
ОП 2018/04/19 04:31:05  №1176480 13
Проверил в старом треде все оставшиеся задачи и посты, начиная с 30 марта:

- >>1176468 - задача про кредит и задача про вектор https://repl.it/repls/AcclaimedWhirlwindSoftwareengineer
- >>1176469 - почему в задаче про кредит не работает if ($a || $b || $c > $d) ?
- >>1176470 вопрос про ssh agent
- >>1176471 про просмотрщик картинок
- >>1176476 про ООП и https://github.com/mlmn/vector.loc/

Если вы писали в прошлом треде и вам не ответили - напомните о себе тут.
someApprentice 2018/04/23 16:28:54  №1178355 14
>>1176471
>Какие ты видишь решения проблемы?
Я ещё не освоился с JS, но пока могу сказать, что это нужно разделить либо на отдельные функции, либо разбить на два класса - Helper и Handler, который вешает обработчики (к примеру, Handler.prototype.handleClickOnImg...).

>> var fullsize = $('.fullsize');
>Не лучше ли сохранять ссылку в переменной, а не искать каждый раз этот класс по всему дереву DOM?

>> Этот элемент нужно искать именно каждый раз когда мы делаем клик, потому что, при каждом открытии, он, каждый раз, создаётся новый.
ну все равно, можно сохранять ссылку на него, а не искать в DOM.

Разве эта переменная и так не ссылка на объект jQuery?

>Что-то мне кажется, для добавления обертки надо опять откатываться к яваскрипту. Либо добить решение с флексбоксом. Вот такой вот он, CSS. Предлагай свои идеи.
У меня идеи закончились когда не получилось отцентировать картинку. Мне нравится вариант с высчитом размеров картинки и центрирования с помощью double translate, потому что мы, в любом случае, обращаемся к js чтобы вывести popup - ничего страшного если с его помощью и размеры посчитать.
Ответы: >>1180024 >>1182086 >>1196643
someApprentice 2018/04/26 11:01:25  №1180024 15
>>1178355
>>Какие ты видишь решения проблемы?
>Я ещё не освоился с JS, но пока могу сказать, что это нужно разделить либо на отдельные функции, либо разбить на два класса - Helper и Handler, который вешает обработчики (к примеру, Handler.prototype.handleClickOnImg...).
Я ещё подумал, что можно разить ещё на отдельные классы, например PopUp и поместить в него все методы связанные с PopUp'ом. Например, PopUp.handle(); или PopUp.resize() и т.д.

Я только не знаю насколько это будет читабельно https://codepen.io/anon/pen/YLGNRY?editors=0010
Мне лично нравится такое решение.
Ответы: >>1182086 >>1182086
someApprentice 2018/04/30 13:25:22  №1182086 16
>>1180024
Обновил код https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js

Я изначально старался чтобы код был максимально простым, но с расширением он начал становиться более запутанным. Мне не хватает опыта. Нужно закончить задачу с чатом.

Ответьте пожалуйста на пару вопросов выше >>1180024 >>1178355

Спасибо.
Ответы: >>1196647
130-450 Аноним 2018/05/25 10:45:22  №1196643 17
>>1178091

Формы вроде "зделаешь" не учтены, но в общем, решено правильно.

>>1178355

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

Начнем с вопроса, как можно инициализировать код и подключать обработчики.

1) "классический" вариант: подключаем скрипты в шапке документа, содержащие функции, а в коде прописываем обработчики в атрибутах вроде <button onclick="..">, которые вызывают эти функции.

Плюс:

- простота и понятность, можно в один клик перейти к функции
- обработчики работают в момент появления элемента на странице (браузер парсит HTML по мере получения и отображает частично загруженную страницу), нет промежутка времени, когда они "мертвые"
- нет проблем с навешиванием обработчиков на динамически доабвляемый на страницу контент

Минус:

- скрипты в шапке блокируют разбор HTML до их загрузку и нешуточно замедляют загрузку страницы на мобильном соединении если их много (с HTTP/2 это чуть улучшилось, но все равно мешает загрузке)

2) вешаем обработчики через функции вроде $(document).ready() в внешних файлах. Этот подход описан довольно давно (статья 2006 года http://alistapart.com/article/behavioralseparation ).

Плюс:

- достигается полное отделение JS от HTML (некоторые вообще против inline-скриптов и атрибутов onxxx)
- это подается под соусом progressive enhancement
- скрипт не требуется загружать заранее в шапке, его можно загрузить асинхронно уже после загрузки страницы

Минус:

- не очевидно, как найти обработчик для кнопки. Это отчасти решается при грамотной организации кода (например, если у каждого виджета или страницы свой управляющий JS-файл и он небольшой, то понятно, что обработчик надо искать в нем)

Особенно неявно все сделано в bootstrap. Там часто наличие определенного класса или атрибута на элементе вызывает появление на нем обработчика. Это очень неочевидная схема.

- код инициализации может разрастаться со временем и часто работать вхолостую (опять же, грамотное разделение на небольшие файлы может помочь)
- не всегда получается навесить обработчик для динамически добавляемого контента (отчасти решается навешиванием обработчика не на каждый элемент, а на уровень выше в DOM)
- кнопка "мертвая" с момента появления до момента загрузки скрипта и срабатывания события docuemnt ready (решение: либо делаем graceful degradation, чтобы до загрузки скрипта кнопка работала без JS, либо скрываем кнопку до инициализации, например, прописав ей класс с visibility: hidden и снимая этот класс при инициализации). Кстати, про "мертвые" кнопки по моему нигде не пишут, неужели я один знаю про эту особенность?

3) смешанные варианты

Например, вариант 1, но с асинхронной загрузкой кода или вариант 2, с инициализацией не во внешнем файле, а в inline-скрипте.

Проблемы, встречающиеся на больших сайтах:

Проблема: большой объем кода. Трудно разобраться, надо грузить много лишнего кода, который не нужен на странице.
Решение: разбиваем код на файлы. Критерии разбиения могут быть разные, например: один класс на файл, один файл на страницу или раздел, один файл на каждый виджет. Главное, чтобы там была какая-то логика.

Например, в идеологии БЭМ мы можем каждый виджет (элемент страницы) делать независимым и класть в свою папку, где лежит его шаблон, его стили, управляющие скрипты: https://ru.bem.info/methodology/filestructure/ . Ну например, мы можем сделать отдельную папку для виджета просмотра и добавления комментариев, после чего легко добавлять его на любую страницу.

Разбиение на компоненты используется и в Angular, и в React, но делать его можно и без этих библиотек.

Проблема: синхронные скрипты блокируют загрузку страницы
Решение: используем progressive enhancement и асинхронную загрузку. То есть загружается просто базовая HTML версия страницы, затем асинхронно грузятся скрипты и обогащают страницу.

Проблема: асинхронно загруженный скрипт не знает, есть ли уже в дереве DOM нужные ему элементы или нет
Решение: либо используем document.ready, либо пишем после кода виджета inline-скрипт, который вызывает фукнцию инициализации явно. Во втором случае элемент инициализируется раньше, чем если бы мы ждали события ready.

Проблема: скрипты могут иметь зависимости и их требуется грузить в определенном порядке. Например, скрипт, использующий jQuery, можно запускать только после загрузки этой библиотеки.
Решение: модули, ES6 модули, AMD, загрузчики вроде require.js. Они позволяют указать зависимости модулей друг от друга.

Проблема: элементы не реагируют на события до загрузки управляющего скрипта
Решение: либо используем graceful degradation (например, ссылка до загрузки скрипта работает как ссылка, а после - как кнопка) либо скрываем элементы. При скрытии желательно использовать visibility: hidden или opcaity, чтобы верстка не прыгала при появлении элемента.

Проблема: в разных скриптах может оказаться функция или переменная с одинаковым именем.
Решение: префиксы в именах функций или модули.

Ответы на вопросы:

> Я ещё не освоился с JS, но пока могу сказать, что это нужно разделить либо на отдельные функции, либо разбить на два класса - Helper и Handler, который вешает обработчики (к примеру, Handler.prototype.handleClickOnImg...).

Не уверен, что в этом есть смысл, разбивать код одного виджета на 2 части.

Кстати, по поводу закрытия при клике на фон - видел такую реализацию, что при наведении на фон (за пределами попапа) курсор превращается в крестик. Чтобы намекнуть, что он закрывает попап. А при наведении на превьюшку курсор можно превращать в лупу.

По коду: https://codepen.io/anon/pen/YLGNRY?editors=0010

Не очень понятно, зачем там строка this.fullsize = $('.fullsize') встречается 2 раза.

> var content = $('<img/>', {class: 'fullsize', src: src});
> $(content).on('load', function() {

Нет ли тут риска, что событие load может произойти до навешивания обработчика? Я не уверен, как все это работает, но по моему src было бы безопаснее задавать после навешивания обработчика.

Нет индикации того, что идет загрузка.

В коде очень глубокая вложенность. 3-4 уровня это максимум.

Это сделано очень неудачно:

> много строк...
> this.visible = true;
> }
> }.bind(this));

Непонятно, к чему вообще относится bind(this). Не надо так писать, огромную функцию и после нее сразу же bind. Вообще, это плохая идея делать гигантские анонимные функции. Ее надо разбить на функции поменьше. Зачем вообще вкладывать несколько функций друг в друга, когда можно их писать просто вертикально друг над другом?

Непонятно, какие методы у объекта публичные, а какие приватные и не должны вызываться снаружи.

По коду https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js

Вот тут видна проблема работающих вхолостую скриптов. На странице может не быть постов, которым требуется превью, а скрипт для них все равно запустится и повесит обработчики.

Также, здесь ставится глобальный обработчик в PostPreview, который будет вызываться при любом движении мыши на странице. Обработчики в атрибутах имеют то преимущество, что они вызываются только при наведении мыши на ссылку. Но конечно имеют и недостатки.

Это конечно скорее проблема плохого дизайна обработчиков событий в браузере, что нам приходится дергать JS скрипт на каждое событие прокрутки или движения мыши. Причем они еще и синхронные - пока обработчик не отработает, браузер ждет и ничего не делает.

Тут в коде та же проблема- огромная вложенность и стремление писать стены кода вместо разделения на функици.

При отправке запроса желательно сделать индикатор. На доброчане, например, яблочко крутится, как я помню, при наведении на ссылку.

Если код состоит из отдельных независимых классов, может стоит разбить его на отдельные файлы.

Если пост есть на странице, возможно не требуется дергать API.

jQuery по умолчанию отключает кеширование в GET-запросе добавлением случайного параметра в URL. Если посты редко меняются, имеет смысл включить кеширование и на сервере отдавать заголовки для безусловного кеширования на небольшое время. А может, еще и поддерживать кеширование через if-modified-since.

В обработчике scroll уменьшение частоты вызовов лучше сделать отдельной функцией, можно даже найти готовую, они называются вроде debounce ( https://davidwalsh.name/javascript-debounce-function ). Это явно стоит вынести в отдельную функцию.

В обработчике попапа, возможно, стоит реагировать на $(window).resize и обновлять позицию попапа, опять же, с применением debounce.
Аноним 2018/05/25 10:47:52  №1196647 18
>>1180542

Увы, ideone теперь тоже сломан, перекатывайтесь куда-нибудь еще.

>>1181775

Школьник может платить от 0 до 5000 р в месяц. Он платит как можно больше, чтобы быстрее выплатить кредит и меньше платить процентов. То есть он платит меньшее из чисел (5000, остаток долга).

Код выглядит примерно так:

- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000

«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.

Ответ тогда получится правильный.

Также, там сначала добавляются проценты, а потом школьник платит. У тебя наоборот.

>>1182086

Вот кстати по чату, очень бы хотелось, чтобы ты для себя сделал первым приоритетом простой, понятный код. Чтобы в нем было легко разбираться. Мы же в PHP разделяем код на классы, соблюдаем правила оформления, пишем комментарии - хотелось бы и в JS то же самое.

Сторонние скрипты лучше положить в отдельную папку от своих.

>>1182092

А какой в этом смысл? Достаточно проверить половину символов.

А так, решено верно.

>>1182336

Посмотри в инструментах разработчика (Ctrl + Shift + I), нет ли ошибок на вкладке Network и Console. Не надо гадать.