Заметки про OSX, часть 1
Получил презент от конторы - заряженный MacBook AIR. Начал понемногу осваивать OSX. Честно говоря, я не думал, что она покажется мне такой странной после нескольких версий Windows и штук пяти различных Linux DE. Здесь почти всё подругому. Поэтому я решил, что имеет смысл строчить небольшие заметки про особенности OSX.
- Добавить второй язык в систему несложно. Это можно сделать в системных настройках. Настоящим же квестом было понять как тут переключать раскладки. Все стандартные известные мне схемы тут же дали сбой. Ни ctrl+shift, ни alt+shift, ни ctrl+alt, ни capslock... Оказывается cmd+пробел. Но.... И эта комбинация клавиш не работает. По ней запускается Spotlight поиск. Его нужно в настройках сочетаний клавиш предварительно отключить. Но... Всё равно не работает. Теперь нужно включить hotkeys для смены раскладки. Называется графа очень не очевидно: Inpus Sources -> Select the previous input sources.
- По-умолчанию все окна занимают не всю область экрана. Часть съедает системная панель, дофига и больше съедает докер, и приличный такой зазор остаётся по бокам. Через этот зазор виден рабочий стол. В чём смысл так нерационально тратить пространство я не понял.
- Набор кнопок у заголовка окна похож на привычный... Но кнопка закрытия окна закрывает окно, не выключая приложения. Как на android-е. Для выхода нужно воспользоваться какой-нибудь специальной опцией в меню.
- Кнопка развернуть работает как-то специфично. Как вернуть окну прежний размер я пока не понял. Можно навести мышь на то место где ранее был заголовок окна и подождать пока он появится. А там уже снова нажать на эту кнопку. Полагаю, что должны быть способы и поудобнее.
- Скроллить можно и неактивные окна. Тачпадом. Т.е. тачпад скроллит то окно, над которым курсор, не передавая в него фокус. Непривычное, но интересное поведение.
- В качестве проводника по файлам какое-то упрощённое приложение под названием Finder. В нём по умолчанию нет адресной строки. А может оной и вообще нет. По клавише enter при активном элементе не происходит перехода внутрь него... вместо этого система предлагает его переименовать. Backspace не возвращает вас на уровень выше, а вот cmd+вверх возвращает.
- Дебильная система со скроллбаром. Он отображается везде только тогда, когда вы скроллите. А до тех пор не всегда даже понятно, помещается ли весь контент в блок, или же его нужно проскроллить. UPD: это настраивается.
- На MacBook-ах очень удобный тачпад. Главная его идея в том, что он целиком является одной прожимаемой кнопкой. И клик будет защитан именно тогда, когда кнопка прожмётся. С характерным звуком. Гораздо удобнее, чем любой другой тачпад, которым мне приходилось пользоваться. Нет ложных срабатываний. Помимо прочего этот тачпад по разному реагирует на одно и два прикосновения одновременно. По сути тут есть дву-пальцевые жесты. Очень удобно скроллить ими.
- В стандартных интерфейсах ОС я часто сталкиваюсь с непониманием - сработала ли кнопка или нет. Обычно становится ясно только спустя некоторое время.
- По субъективным ощущениям ОС работает медленнее, чем мой аналогичный по железу Dell XPS 13. А ещё монитор не сенсорный и не переворачивается как на Dell-е :)
- Меню у всех приложений не в окнах, а верхней панели. Тянуться приходится далеко. Меня эта фича ещё в Unity раздражала. Впрочем Unity много странных UI решений из OSX спёр. Тот же поиск и докер.
- При копировании и переключении языка система всплывающей подсказкой уведомляет вас об этом. Классная фича. Мне на Mint-е такой не хватает.
- Даже текстовые комбинации клавиш другие. Придётся изучать новые. К примеру я пока не знаю, как перенести курсор на одно слово левее. Но нашёл альтернативу клавишам home и end: cmd+вправо и cmd+влево.
- С непривычки часто включаю контекстное меню на тачпаде двумя пальцами... случайно.
- Хотел проставить браузер Vivaldi. Официальный сайт предложил мне скачать некий dmg-файл. Что с ним делать система не знает. Пока не разбирался почему. А в Store его пока нет. UPD: оказывается установщик просто молча дохнет, но таки запускается.
- Этот Store притча во языцах. По дурацки построенное, не очевидное и не продуманное приложение с кучей бюрократии. Прежде чем я смог установить yandex.disk оттуда мне пришлось по 10 раз заполнять одну и ту же форму, кликать одни и те же кнопки, пока я не понял что именно и в какой последовательности от меня хотят. Одна из форм чуть ли не мою родословную затребовала.
V8 & unicode RegExp-ы
Не так давно в V8 движок добавили поддержку флага /u (т.е. поддержку unicode) для регулярных выражений. В nodeJS можно подключить флагом --harmony_unicode_regexps. Вот небольшой обзор по новым возможностям. При установленном флаге . понимает иероглифы, их же стало можно использовать в описании регулярного выражения без экранирования, появилась поддержка i флага.
Но! Они недобавили самого вкусного ― \p{L}. При помощи модификатора \p можно кратко описать многие вещи (см. раздел Unicode Categories). К примеру можно описать в пару символом регулярку, которая будет проверять принадлежность символа к алфавиту какого-либо языка. Например, /^\p{L}[\p{L}\d-_ ]+$/u отлично подойдёт для валидации имени пользователя, не поставив в незавидное положение ни грузин, ни китайцев, ни русских. Но отлично отфильтрует рандомный бред с клавиатуры.
Надеюсь, что это временно. А пока можно воспользоваться, к примеру, XRegExp-ом.
Подключаем HTTPS к Nginx за счёт Let’s Encrypt
Небольшая заметка про подключение letsencrypt на сайт с nginx сервером. За основу взял хабра-статью от @questor-а. Наша задача добавить поддержку https на сайт малой кровью. letsencrypt позволяет нам это сделать, взяв на себя всю чёрную работу по подготовке, выдаче, загрузке и обновлению сертификатов (подробнее). Всё нижеописанное я привожу для linux debian-like систем.
Принцип работы
Для подключения HTTPS необходимы сертификаты (для шифрования и аутентификации). Причём эти сертификаты должны быть выданными доверенными серверами, список которых вшит в браузеры. Обычно это дело было платным, но с недавних пор, появилось несколько доступных и бесплатных альтернатив. Одна из которых это Let’s Encrypt.
Let’s Encrypt выпускает сертификаты бесплатно и в автоматическом режиме на 3 месяца. Для работы с ним подготовлено ПО с открытым кодом и есть открытое API для взаимодействия вручную. Мы воспользуемся готовым рекомендованным ПО.
Принцип работы этого ПО заключается в том, что сервер запрашивает у letsencrypt-центра выпуск новых сертификатов для указанных доменным имён. Для этого letsencrypt-центр ломится на ваш сервер по конкретным URL-ам с этими доменными именами, и убеждается в том, что они принадлежат вам. Затем выпускает новые сертификаты и передаёт их на сервер сайта. ПО складирует их в указанной директории. Вам остаётся лишь подключить их к nginx и настроить автоматическое обновление по cron-у.
Подготовка, подключение и обновление под катом.
Resize изображений на стороне браузера
В этой заметке я опишу, как, относительно несложным способом, можно организовать resize изображений на стороне браузера перед отправкой на сервер.
Для начала нам потребуется <input type="file"/>. Без него нам не открыть диалог для выбора файла. Чтобы вызвать его вручную необходимо в обработчике вида onclick (onkeydown и пр. отпадают из-за Firefox) вызвать file.click(). Вызвать диалог в произвольный момент времени не получится.
Отслеживаем изменение выбора файла по onchange. Сам же файл достаём из file.files[index]. Если наш <input/> работает не в multiple режиме, то index, соответственно, равен 0. Присмотревшись к свойствам этого объекта мы увидим его mime тип, размер, имя файла. Но не содержимое.
Для получения содержимого воспользуемся FileReader-ом.
const reader = new FileReader();
reader.onload = e => { e.target.result; /* base64 string */ };
reader.readAsDataURL(file);
Через него получаем DataURL вариант содержимого файла (асинхронно). Затем создаём новый Image, вешаем обработчик на onload, задаём этот dataURL ему как аттрибут src. В результате получаем валидный <img/> тег с загруженным готовым к использованию изображением.
Resize изображения будем осуществлять за счёт <canvas/>. У context-а canvas-а есть метод drawImage, который сделает за нас всю грязную работу. Ниже пример работы с ним (стояла задача вписать изображение в определённые рамки, но только если оно превышает эти сами рамки):
const canvas = document.createElement('canvas');
const w_ratio = img.width / width;
const h_ratio = img.height / height;
let ratio = Math.max(w_ratio, h_ratio);
if(ratio < 1)
ratio = 1;
const w = Math.floor(img.width / ratio);
const h = Math.floor(img.height / ratio);
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, w, h);
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, w, h);
return canvas.toDataURL('image/jpeg', 80);
Обратите внимание на то, что <canvas/> даже не обязательно цеплять к DOM-у браузера, и тем более делать его видимым. В результате получаем снова dataURL, но уже правильного вида и размера. Но что нам теперь с ним делать?
Вариантов много. К примеру можно послать на сервер строкой, как и другие поля. Но можно воспользоваться FormData, и тогда работа с такой выдачей клиента ничем не будет отличаться от обычной:
const fd = new FormData(form);
fd.append('image', blob);
Обратите внимание на blob. Дело в том, что для маскировки под обычный input[type=file] нам нужно нашу dataURL перевести в Blob вариант. Я взял готовое решение со stackoverflow:
function dataUriToBlob(dataURI)
{
let byteString;
if( dataURI.split(',')[0].indexOf('base64') >= 0 )
byteString = atob(dataURI.split(',')[1]);
else
byteString = window.unescape(dataURI.split(',')[1]);
// separate out the mime component
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
const ia = new Uint8Array(byteString.length);
for(let i = 0; i < byteString.length; i ++)
ia[i] = byteString.charCodeAt(i);
return new Blob([ ia ], { type: mimeString });
}
Задача решена. Относительно без крови. Однако, мы воспользовались FormData, FileReader, Blob, Uint8Array, Canvas. Тот же самый IE9 всего этого не умеет.
Об IE9 замолвите слово
Минутка гнева… Internet Explorer 9 не умеет:
- Placeholder-ы
- FormData, FileReader, Blob, Uint8Array
- Flexbox
Помимо этого обладает ужаасным набором инструментов, постоянно дохнет и очень медленно работает. В общем, этот браузер не так уж и далеко ушёл от своего 8-го собрата.