html5 – Stepan Suvorov Blog https://stepansuvorov.com/blog Release 2.0 Thu, 22 Oct 2015 08:06:23 +0000 en-US hourly 1 https://wordpress.org/?v=6.3.1 AngularJS и проверка данных формы https://stepansuvorov.com/blog/2015/06/angularjs-%d0%b8-%d0%bf%d1%80%d0%be%d0%b2%d0%b5%d1%80%d0%ba%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85-%d1%84%d0%be%d1%80%d0%bc%d1%8b/ https://stepansuvorov.com/blog/2015/06/angularjs-%d0%b8-%d0%bf%d1%80%d0%be%d0%b2%d0%b5%d1%80%d0%ba%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85-%d1%84%d0%be%d1%80%d0%bc%d1%8b/#comments Sun, 14 Jun 2015 15:15:52 +0000 http://stepansuvorov.com/blog/?p=2001 Continue reading ]]> AngularJS Validation

Пост состоит из следующих частей:

  • Проверка данных в HTML5
  • AngularJS расширения для валидации
  • Свои кастомные проверки данных на AngularJS
  • Вывод сообщений об ошибках и ng-messages

 

HTML5 валидация данных

В первую очередь следует отметить, что у тега <form> в HTML5 появился атрибут novalidate, который говорит браузеру, что форму валидировать не нужно.

Вспомогательные атрибуты проверки данных:

  • require – говорит о том, что поле обязательно и должно быть заполнено
  • min/max – характерно для элемента input и указывает граничные значения
  • maxlength – для input и textarea, задает максимальное количество символов
  • type – в поле типа мы можем указывать не только text, но так же такие значения как email, url, которые будут провалидированы стандартными правилами. Болле подробно о стандартах тут.
  • pattern – позволяет задать регулярное выражение для проверки поля.

API для проверки данных:

  • checkValidity() – метод, который есть, как у всей формы, так и у каждого элемента. Возвращает true/false.
  • willValidate – свойство, false, когда элемент содержит невалидные данные
  • validity – свойство, содержит объект экземпляр ValidityState
  • validationMessage – содержит сообщение ошибки
  • setCustomValidity(message) – позволяет задать сообщение ошибки

Поиграться с атрибутами проверки и API можно тут.

AngularJS расширения для валидации

Ангуляр автоматически применяется к элементу формы, в текущий $scope будет добавлена ссылка на formCotroller, ключом будет являться значение атрибута name. В нем мы можем найти ссылки на ngModelController для всех элементов формы ( так же по  name). То есть, мы добавили в наше Ангуляр приложение форму:

[html]
<form name=login>
<input name="username">
<input name="password">
</form>
[/html]

После чего в нашем скоуп будут:

[javascript]
$scope.login // formController
$scope.login.username //ngModelController
$scope.login.password //ngModelController
[/javascript]

И при этом каждый объект formController и ngModelController содержит следующие свойства (касательно валидации):

  • $valid – true/false – валидности введенных данных относительно заданных правил
  • $invalid – false/true – обратный к предыдущему
  • $pristine – true, если форма/элемент еще не использовались
  • $dirty – обратные к предыдущему
  • $touched – на элементе произошло событие blur
  • $error – объект ошибки
  • $isEmpty(value) – вспомогательный метод, который проверяет является ли значение undefined, ”, null или NaN
  • $validate() – true/false – запускает все валидаторы зарегистрированные на модели
  • $setValidity(validationErrorKey, isValid) – задание значения валидности для одного из критериев
  • $setPristine()/$setDirty() – сеттеры для $pristine/$dirty
  • $setUntouched()/$setTouched() – сеттеры для $touched

Так же ngModelController содержит свойство $validators, в котором мы можем определять наши методы для проверки данных, то есть:

[javascript]
ngModel.$validators.validCharacters = function(modelValue, viewValue) {
var value = modelValue || viewValue;
return /[0-9]+/.test(value) &&
/[a-z]+/.test(value) &&
/[A-Z]+/.test(value) &&
/\W+/.test(value);
};
[/javascript]

Вот тут можно посмотреть как изменяются свойства в зависимости от изменения значений полей:

Ангуляр полностью дублирует атрибуты валидации HTML5, причем в некоторых случаях оставляя их без изменения (как required), а в некоторых изменяет названия атрибута (ng-maxlength); плюс использует свои дополнительные:

  • required – просто парсит HTML5 атрибут
  • ng-minlength/ng-maxlength – ограничения по количеству символово (как и maxlength)
  • type – использует атрибут HTML5
  • ng-pattern – отличие в том что мы можем подставлять паттерн динамически и ошибка по умолчанию не тригерится наверх (сравнить)

!Внимание:

  • все валидируемые елементы должны содержать директиву ng-model, именно благодаря ней мы имеем доступ к ngModelController
  • если у вас в scope свойство, которая не соответствует критериям, – оно выведено не будет.

Свои кастомные проверки данных на AngularJS

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

C директивой все понятно. Но вот то, как мы вернем потом значение, не так однозначно, особенно в случае асинхронных операций.

Вот пример проверки уникальности записи от ng-newsletter, атрибут-директива для элемента формы, которая следит за изменением значения:

[javascript]
app.directive(‘ensureUnique’, [‘$http’, function($http) {
return {
require: ‘ngModel’,
link: function(scope, ele, attrs, c) {
scope.$watch(attrs.ngModel, function() {
$http({
method: ‘POST’,
url: ‘/api/check/’ + attrs.ensureUnique,
data: {‘field’: attrs.ensureUnique}
}).success(function(data, status, headers, cfg) {
c.$setValidity(‘unique’, data.isUnique);
}).error(function(data, status, headers, cfg) {
c.$setValidity(‘unique’, false);
});
});
}
}
}]);
[/javascript]

А вот так (взято из оф доки) мы можем переопределить стандартную проверку:

[javascript]
app.directive(‘overwriteEmail’, function() {
var EMAIL_REGEXP = /^[a-z0-9!#$%&’*+/=?^_`{|}~.-]+@example\.com$/i;

return {
require: ‘ngModel’,
restrict: ”,
link: function(scope, elm, attrs, ctrl) {
if (ctrl && ctrl.$validators.email) {

ctrl.$validators.email = function(modelValue) {
return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
};
}
}
};
});
[/javascript]

И есть еще один интересный пример с хабра и использованием свойств котроллера модели $parsers и $formatters:

[javascript]
mod.directive(‘strongPassRequired’, function () {
var isValid = function(s) {
return s && s.length > 5 && /\D/.test(s) && /\d/.test(s);
};

return {
require:’ngModel’,
link:function (scope, elm, attrs, ngModelCtrl) {

ngModelCtrl.$parsers.unshift(function (viewValue) {
ngModelCtrl.$setValidity(‘strongPass’, isValid(viewValue));
return viewValue;
});

ngModelCtrl.$formatters.unshift(function (modelValue) {
ngModelCtrl.$setValidity(‘strongPass’, isValid(modelValue));
return modelValue;
});
}
};
});
[/javascript]

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

 

Вывод сообщений об ошибках и ng-messages

Начиная с Angular 1.3 появилась возможность подключить прекрасный модуль ngMessages, который серьезно упрощает работу по выводу ошибок. В старых версиях нам приходилось выдумывать что-то с ng-if/ng-show, а теперь все можно сделать так:

[html]
<form name="demoForm">
<input name="amount" type="number" ng-model="amount" max="100">
<div ng-messages="demoForm.amount.$error">
<div ng-message="number">Should be a number</div>
<div ng-message="max">The number is too large.</div>
</div>
</form>
[/html]

Поиграться с кодом можно тут.

!Внимание: при этом не забудьте подключить в зависимости ваш модуль:

[javascript]
angular.module(‘app’, [‘ngMessages’]);
[/javascript]

ну и конечно подключить .js файл.

Стилизация валидируемых полей

Для каждого состояния Ангуляр добавляет специальный класс:

  • ng-valid/ng-invalid
  • ng-valid-[key]ng-invalid-[key] – отдельный для каждого ключа заданного через  $setValidity
  • ng-pristine/ng-dirty
  • ng-touched/ng-untouched
  • ng-pending – ждет асинронной валидации от $asyncValidators

 

Сейчас вот задался вопросом: “Почему до сих пор нет никакого готового (и популярного) модуля для валидации данных?” Чтобы можно было на всю форму (например) навесить директиву и передать ей конфиг заполняемых полей. Если что-то знаете в тему – подскажите пожалуйста в комментариях. Иначе прийдется делать свой велосипед.

]]>
https://stepansuvorov.com/blog/2015/06/angularjs-%d0%b8-%d0%bf%d1%80%d0%be%d0%b2%d0%b5%d1%80%d0%ba%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85-%d1%84%d0%be%d1%80%d0%bc%d1%8b/feed/ 10
Что нового в HTML5 и CSS3 https://stepansuvorov.com/blog/2014/09/%d1%87%d1%82%d0%be-%d0%bd%d0%be%d0%b2%d0%be%d0%b3%d0%be-%d0%b2-html5-%d0%b8-css3/ https://stepansuvorov.com/blog/2014/09/%d1%87%d1%82%d0%be-%d0%bd%d0%be%d0%b2%d0%be%d0%b3%d0%be-%d0%b2-html5-%d0%b8-css3/#respond Tue, 09 Sep 2014 23:40:47 +0000 http://stepansuvorov.com/blog/?p=1308 Continue reading ]]>

Сразу оговорюсь: цель этого поста – упорядочить для себя инфомрацию, которая накопилась с 2009 года. Возможно это будет полезно тому, кто только пытается проникнуться последними веяниями HTML и CSS.

HTML5

Обновление тегов (сокращенная форма)

  • <!DOCTYPE html>
  • <meta charset=”UTF-8″>
  • <script src=”script.js”></script>
  • <link rel=”stylesheet” href=”styles.css”>

Новые семантические элементы

  • section
  • header/footer
  • aside
  • nav
  • article
  • main
  • figure/figurcaption

Новые атрибуты формы

  • placeholder
  • autofocus
  • autocomplete
  • required
  • pattern
  • list
  • multiple
  • novalidate
  • formnovalidate
  • form
  • formaction
  • formenctype
  • formmethod
  • formtarget

Поддержка аудио и видео

Рисование используя элемент canvas

Локальное хранилище

CSS3

Скруглённые рамки

Тени блоков и тени текста

Анимация

Градиенты

Множественные бекграунды

Шрифты

Литература

]]>
https://stepansuvorov.com/blog/2014/09/%d1%87%d1%82%d0%be-%d0%bd%d0%be%d0%b2%d0%be%d0%b3%d0%be-%d0%b2-html5-%d0%b8-css3/feed/ 0
Многопоточность в JavaScript https://stepansuvorov.com/blog/2013/12/webworkers/ https://stepansuvorov.com/blog/2013/12/webworkers/#comments Wed, 04 Dec 2013 09:52:38 +0000 http://stepansuvorov.com/blog/?p=932 Continue reading ]]>

Да, в JavaScript тоже есть многопоточность(либо подобие) и реализована по средством инструмента Web Workers, о использовании которого и поговорим в данном посте.

Идея реализации: “тяжелые” операции, которые можно выполнять асинхронно(не блокирую работу браузера), выносятся в отдельные модули-файлы; это может быть: обработка большого количества данных, кеширование, проверка правописания, фильтрация изображений на canvas. В браузере для каждого такого файла создается объект Worker, по средством которого и осуществляется коммуникация.

Другими словами: используя технологию Web Workers можно избежать появления вот этого сообщения

Проверка поддержки браузером

Для проверки поддерживает ли браузер технологию Web Workers достаточно проверить наличие объекта window.Worker:

if (!!window.Worker)
{
    //поддерживается
}

 Простой пример

На сайте w3 дали довольно наглядный пример, который я немного модифицировал расширив передачу данных в обе стороны. Итак, у нас есть 2 файла: основной(для простоты пишем внутри хтмл файла) test.html и файл воркера worker.js. Мы задались целью выводить на экран простые числа в заданном диапозоне, но, так как операция по определению является ли число простым довольно ресурсоемкая, особенно для больших чисел, мы вынесем ее в отдельный фоновый поток (worker). Код этой функции и будет находиться в файле worker.js.

Итого, test.html:

<!DOCTYPE HTML>
<html>
<body>
<output id="result"></output>
<script>
    var worker = new Worker('worker.js');
    worker.onmessage = function (event) {
        document.getElementById('result').textContent += ', ' + event.data;
    };
    worker.postMessage({from:17,to:50});
</script>
</body>
</html>

и файл worker.js:

onmessage = function(event)
{
    var n = event.data.from;
    while (n < event.data.to) {
        n += 1;
        if(isPrime(n)){
            // found a prime!
            postMessage(n);
        }
    }
};

function isPrime(number){
    for (var i = 2; i <= Math.sqrt(number); i += 1){
        if (number % i == 0){
            return false;
        }
    }
    return true;
}

Для тех,  кто хочет поиграться с примером, – пожалуйста сюда.

Теперь немного комментариев.

var worker = new Worker('worker.js');

создаем объект Worker. Объект не запускается до полной загрузки и выполнения файла. Если путь к объекту Worker возвращает ошибку 404, его выполнение прекращается без уведомлений.

worker.onmessage = function (event) {

прописываем колбэк, который выполнится при вызове метода postMessage внутри воркера

worker.postMessage({from:17,to:50});

отправляем в воркер сообщение с параметрами диапазона ( мы хотим получить все простые числа в диапозоне с 17 до 50 )

Перейдем к коду воркера:

onmessage = function(event){

функция будет вызвана, при обращении к метод worker.postMessage() в основном скрипте

 var n = event.data.from;

доступ к данным внутри метода можно получить через event.data

 

Взаимодействие  с объектами Worker

Как уже было показано на примере, взаимодействие с воркерами осуществляется путем потоковой передачи сообщений (метод postMessage – для отправки и колбэк onmessage – для приема).

Колбэк на получение сообщения можно также навешивать следующим способом:

addEventListener('message', function(e) {

именно он является рекомендуемым для использования.

 

Ограничения Web Worker

К чему можно обращаться внутри worker-скрипта:

У worker-скрипта нет доступа к:

  • Модель DOM (она не ориентирована на многопоточное исполнение)
  • Объект window
  • Объект document
  • Объект parent

Методы postMessage и onmessage являются глобальными для ворвера, и к ним можно обратиться как на прямую, так и через this и self.

Максимальное количество workerов – 256, после чего стек переполняется и пишет ошибку:

Maximum number of Web Worker instances(256) exceeded for this window.

 

Отлов ошибок

Также, как и с сообщениями, мы можем подписаться на получение ошибок:

 worker.addEventListener('error', onError, false);

 

Динамическое создание worker-скриптов

Иногда возникает необходимо создать worker-скрипт динамически(!внимание именно worker-скрипт, а не сам worker), в зависимости от различных условий. В таком случае создание worker из отдельного файла нас не устраивает и мы должны воспользоваться вторым способом – через подготовленный объект Blob, а точнее – ссылки на него.

Вот так это будет выглядеть в коде

var script = "onmessage = function(e) { postMessage('msg from worker'); }";
var blob = new Blob([script]);
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);

Для удобства скрипт изначально пожно записать в script тег:

<script id="worker1" type="javascript/worker">
    //...код вашего воркера
</script>

а потом получить содержимое:

var script = document.querySelector('#worker1').textContent;

!Внимание: не забудьте поставить тип javascript/worker, это предотвратит разбор кода js-движком браузера.

 

Литература

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

]]>
https://stepansuvorov.com/blog/2013/12/webworkers/feed/ 1
Получаем координаты используя HTML5 Geolocation API https://stepansuvorov.com/blog/2013/08/html5-geolocation-api/ https://stepansuvorov.com/blog/2013/08/html5-geolocation-api/#respond Fri, 16 Aug 2013 09:46:58 +0000 http://stepansuvorov.com/blog/?p=1177 Continue reading ]]> Небольшая заметка с примерами использования возможностей геолокации современных браузеров.

Все что нас интересует происходит с объекте navigator.geolocation, поэтому чтобы проверить поддерживает ли браузер данную возможность можно выполнить следующий код:

if ("geolocation" in navigator) {
  /* geolocation поддерживается */
} else {
  /* geolocation НЕ поддерживается */
}

Для получения текущего местоположения используется метод navigator.geolocation.getCurrentPosition() имеющий следующий синтаксис:

getCurrentPosition(success, error, options)

где

success - колбэк на успешное получение координат
error - колбэк обработки ошибки
options - опции

Самый простой пример получения координат:

navigator.geolocation.getCurrentPosition(function(position) {
  console.log(position.coords.latitude, position.coords.longitude);
});

Пример на jsfiddle.

Также объект geolocation содержит метод watchPosition(), который устанавливает хэндлер на событие изменения локации. Принимает параметры аналогичные параметрам метода getCurrentPosition().

Еще один пример с использованием google maps.

 

Полезные ссылки:

HTML5 Geolocation API(Presentation from HTML5 Camp)

Using geolocation

The Geolocation API

]]>
https://stepansuvorov.com/blog/2013/08/html5-geolocation-api/feed/ 0
Canvas – это просто! https://stepansuvorov.com/blog/2012/08/canvas-%d1%8d%d1%82%d0%be-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%be/ https://stepansuvorov.com/blog/2012/08/canvas-%d1%8d%d1%82%d0%be-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%be/#comments Tue, 21 Aug 2012 07:45:49 +0000 http://stepansuvorov.com/blog/?p=467 Continue reading ]]> Наконец-то появилось время разобрать принципы анимации с использованием HTML canvas элемента.

Вот что получилось:


Подробности под катом.

Итак поехали:

<canvas id="tutorial" width="150" height="150"></canvas>

– добавляем HTML элемент в страницу. Для рисования необходимо обратиться к нему на javascript и получить контекст:

var canvas = document.getElementById('tutorial');
var ctx = canvas.getContext('2d');

На данный момент 2д – единственный возможный контекст, поэтому с этим тоже не заморачиваемся.

Вот мы и перешли к самой интересной части – нанесение изображения. Объект контекста содержит много различных методов, например:

ctx.fillRect (5, 5, 55, 50); // рисуем прямоугольник

Мы можем задать стиль для нашего прямоугольника:

ctx.fillStyle = "rgb(35, 200, 35)"; // сначала задаем стиль
ctx.fillRect (5, 5, 55, 50); // потом рисуем прямоугольник

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

canvas

А в чем заключается анимация? В том что мы по времени перерисовываем картинку, или другими словами – меняем координаты/параметры движимых объектов.

Как видите ничего сложного нет. Нужны только фантазия и справочник по методам.

С кодом примера можно поиграться вот тут: http://learn.javascript.ru/play/lZqarb

Добавлю еще две иллюстрации, которые я нашел в сети, о том как рисовать дуги:

arc(x, y, radius, startAngle, endAngle, anticlockwise);

О принципе отсчета угла:

О радианах:

Источник этих прекрасных эскизов.

 

]]>
https://stepansuvorov.com/blog/2012/08/canvas-%d1%8d%d1%82%d0%be-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%be/feed/ 2
Поиграемся с HTML5 history API https://stepansuvorov.com/blog/2012/08/%d0%bf%d0%be%d0%b8%d0%b3%d1%80%d0%b0%d0%b5%d0%bc%d1%81%d1%8f-%d1%81-html5-history-api/ https://stepansuvorov.com/blog/2012/08/%d0%bf%d0%be%d0%b8%d0%b3%d1%80%d0%b0%d0%b5%d0%bc%d1%81%d1%8f-%d1%81-html5-history-api/#comments Sun, 12 Aug 2012 17:49:11 +0000 http://stepansuvorov.com/blog/?p=435 Continue reading ]]>
Никакой военной тайны в статье не открою, но открою глаза для тех, кто не работал с history API. Чтобы понять нужно вам или нет, просто кликните сюда и понаблюдайте за адресной стройкой браузера. Если эта возможность не удивила – можете дальше не читать статью. (Прошу обратить внимание: мы меняем содержание адресной строки без перезагрузки страницы, это важно)

Ну а для тех, кто дошел до этого места, попробуем разобрать магию: мы работаем с объектом window.history с помощью javascript. Почитать подробно можно тут. Разбирать очевидные методы типа: go(), back(), forward() мы не будем. Остановимся более подробно на pushState(data, title, url), где

  • data – это данные передаваемые странице(можно пустой объект)
  • title – название конкретного состояния(тоже можно оставить пустым)
  • url – то что мы хотим записать сразу после домена

Вот пример с конкретными данными:

history.pushState({}, '', '/someurl/that/you/want/to/see/in/location')

Как видите  – ничего сложного.

Где это необходимо использовать? В сервисах, где большая часть логики на стороне клиента, а обращения к серверу идут аяксом: при этом хотелось держать в браузере валидную историю переходов.

На всякий случай проверяем табличку совместимости с вашими поддерживаемыми браузерами.

Вот полный код того, что происходило вначале: http://learn.javascript.ru/play/S60sJ (в песочнице работать не будет, так как она открывается во фрейме)

]]>
https://stepansuvorov.com/blog/2012/08/%d0%bf%d0%be%d0%b8%d0%b3%d1%80%d0%b0%d0%b5%d0%bc%d1%81%d1%8f-%d1%81-html5-history-api/feed/ 1